Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Examples

ctk.c

Go to the documentation of this file.
00001 /**
00002  * \defgroup ctk CTK graphical user interface
00003  *
00004  * The Contiki Toolkit (CTK) provides the graphical user interface for
00005  * the Contiki system.
00006  *
00007  * @{
00008  */
00009 
00010 /**
00011  * \file
00012  * The Contiki Toolkit CTK, the Contiki GUI.
00013  * \author Adam Dunkels <adam@dunkels.com>
00014  */
00015 
00016 /*
00017  * Copyright (c) 2002-2003, Adam Dunkels.
00018  * All rights reserved.
00019  *
00020  * Redistribution and use in source and binary forms, with or without
00021  * modification, are permitted provided that the following conditions
00022  * are met:
00023  * 1. Redistributions of source code must retain the above copyright
00024  *    notice, this list of conditions and the following disclaimer.
00025  * 2. Redistributions in binary form must reproduce the above
00026  *    copyright notice, this list of conditions and the following
00027  *    disclaimer in the documentation and/or other materials provided
00028  *    with the distribution.
00029  * 3. The name of the author may not be used to endorse or promote
00030  *    products derived from this software without specific prior
00031  *    written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00034  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00035  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00037  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00039  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00040  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00041  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00042  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00043  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00044  *
00045  * This file is part of the Contiki operating system.
00046  *
00047  * $Id: ctk.c,v 1.1 2006/06/17 22:41:16 adamdunkels Exp $
00048  *
00049  */
00050 
00051 #include <string.h>
00052 
00053 #include "contiki.h"
00054 
00055 #include "ctk/ctk.h"
00056 #include "ctk/ctk-draw.h"
00057 #include "ctk/ctk-mouse.h"
00058 
00059 static unsigned char height, width;
00060 
00061 static unsigned char mode;
00062 
00063 static struct ctk_window desktop_window;
00064 static struct ctk_window *windows;
00065 static struct ctk_window *dialog;
00066 
00067 #if CTK_CONF_MENUS
00068 static struct ctk_menus menus;
00069 static struct ctk_menu *lastmenu;
00070 static struct ctk_menu desktopmenu;
00071 #endif /* CTK_CONF_MENUS */
00072 
00073 #ifndef NULL
00074 #define NULL (void *)0
00075 #endif /* NULL */
00076 
00077 #define REDRAW_NONE         0
00078 #define REDRAW_ALL          1
00079 #define REDRAW_FOCUS        2
00080 #define REDRAW_WIDGETS      4
00081 #define REDRAW_MENUS        8
00082 #define REDRAW_MENUPART     16
00083 
00084 #define MAX_REDRAWWIDGETS 4
00085 static unsigned char redraw;
00086 static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
00087 static unsigned char redraw_widgetptr;
00088 static unsigned char maxnitems;
00089 
00090 static unsigned char iconx, icony;
00091 #define ICONX_START  (width - 6)
00092 #define ICONY_START  (height - 7)
00093 #define ICONX_DELTA  -16
00094 #define ICONY_DELTA  -5
00095 #define ICONY_MAX    height
00096 #define ICONY_MIN    0
00097 
00098 #ifndef ctk_arch_isprint
00099 unsigned char ctk_arch_isprint(char c);
00100 #endif /* ctk_arch_isprint */
00101 
00102 
00103 PROCESS(ctk_process, "CTK Contiki GUI");
00104 
00105 /**
00106  * \defgroup ctkevents CTK events
00107  * @{
00108  */
00109 process_event_t
00110 
00111   /**
00112    * Emitted for every key being pressed.
00113    *
00114    * The key is passed as signal data.*/
00115   ctk_signal_keypress,
00116   
00117   /** Emitted when a widget is activated (pressed). A pointer to the
00118       widget is passed as signal data. */
00119   ctk_signal_widget_activate,
00120   
00121   /** Same as ctk_signal_widget_activate. */
00122   ctk_signal_button_activate,
00123 
00124   /** Emitted when a widget is selected. A pointer to the widget is
00125       passed as signal data. */
00126   ctk_signal_widget_select,
00127   
00128   /** Same as ctk_signal_widget_select. */
00129   ctk_signal_button_hover,
00130 
00131   /** Emitted when a hyperlink is activated. The signal is broadcast
00132       to all listeners. */
00133   ctk_signal_hyperlink_activate,
00134 
00135   /** Same as ctk_signal_widget_select. */
00136   ctk_signal_hyperlink_hover,
00137 
00138   /** Emitted when a menu item is activated. The number of the menu
00139       item is passed as signal data. */
00140   ctk_signal_menu_activate,
00141 
00142   /** Emitted when a window is closed. A pointer to the window is
00143       passed as signal data. */
00144   ctk_signal_window_close,
00145 
00146   /** Emitted when the mouse pointer is moved. A NULL pointer is
00147       passed as signal data and it is up to the listening process to
00148       check the position of the mouse using the CTK mouse API.*/
00149   ctk_signal_pointer_move,
00150 
00151   /** Emitted when a mouse button is pressed. The button is passed as
00152       signal data to the listening process. */
00153   ctk_signal_pointer_button;
00154 
00155 #if CTK_CONF_SCREENSAVER
00156 /** Emitted when the user has been idle long enough for the
00157     screensaver to start. */
00158 process_event_t ctk_signal_screensaver_stop,
00159   /** Emitted when the user presses a key or moves the mouse when the
00160       screensaver is active. */
00161   ctk_signal_screensaver_start;
00162 #endif /* CTK_CONF_SCREENSAVER */
00163 
00164 /** @} */
00165 
00166 
00167 #if CTK_CONF_MOUSE_SUPPORT
00168 unsigned short mouse_x, mouse_y, mouse_button;
00169 #endif /* CTK_CONF_MOUSE_SUPPORT */
00170 
00171 static unsigned short screensaver_timer = 0;
00172 unsigned short ctk_screensaver_timeout = (5*60);
00173 static struct timer timer;
00174 
00175 static void CC_FASTCALL
00176 textentry_input(ctk_arch_key_t c,
00177                 CC_REGISTER_ARG struct ctk_textentry *t);
00178 #if CTK_CONF_MENUS
00179 /*---------------------------------------------------------------------------*/
00180 /**
00181  * \internal Creates the Desktop menu.
00182  *
00183  * Creates the leftmost menu, "Desktop". Since the desktop menu
00184  * contains the list of all open windows, this function will be called
00185  * whenever a window is opened or closed.
00186  */
00187 /*---------------------------------------------------------------------------*/
00188 static void
00189 make_desktopmenu(void)
00190 {
00191   struct ctk_window *w;
00192   
00193   desktopmenu.nitems = 0;
00194   
00195   if(windows == NULL) {
00196     ctk_menuitem_add(&desktopmenu, "(No windows)");
00197   } else {
00198     for(w = windows; w != NULL; w = w->next) {
00199       ctk_menuitem_add(&desktopmenu, w->title);
00200     }
00201   }
00202 }
00203 #endif /* CTK_CONF_MENUS */
00204 /*---------------------------------------------------------------------------*/
00205 static void
00206 arrange_icons(void)
00207 {
00208   struct ctk_widget *icon;
00209 
00210   iconx = ICONX_START;
00211   icony = ICONY_START;
00212   
00213   for(icon = desktop_window.active; icon != NULL; icon = icon->next) {
00214     
00215     icon->x = iconx;
00216     icon->y = icony;
00217     
00218     icony += ICONY_DELTA;
00219     if(icony >= ICONY_MAX ||
00220        icony < ICONY_MIN) {
00221       icony = ICONY_START;
00222       iconx += ICONX_DELTA;
00223     }
00224   }
00225 }
00226 /*---------------------------------------------------------------------------*/
00227 void
00228 ctk_restore(void)
00229 {
00230   ctk_draw_init();
00231 
00232   height = ctk_draw_height();
00233   width = ctk_draw_width();
00234 
00235   arrange_icons();
00236 
00237   redraw = REDRAW_ALL;
00238 }
00239 /*---------------------------------------------------------------------------*/
00240 
00241 
00242 /**
00243  * \addtogroup ctkappfunc
00244  * @{
00245  */
00246 
00247 /*---------------------------------------------------------------------------*/
00248 /**
00249  * Sets the current CTK mode.
00250  *
00251  * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
00252  * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
00253  * keypresses and mouse pointer movements are processed and the screen
00254  * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
00255  * performed and the first key press or pointer movement will cause
00256  * the ctk_signal_screensaver_stop to be emitted. In the
00257  * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
00258  * ignored and no screen redraws are made.
00259  *
00260  * \param m The mode.
00261  */
00262 /*---------------------------------------------------------------------------*/
00263 void
00264 ctk_mode_set(unsigned char m) {
00265   mode = m;
00266 }
00267 /*---------------------------------------------------------------------------*/
00268 /**
00269  * Retrieves the current CTK mode.
00270  *
00271  * \return The current CTK mode.
00272  */
00273 /*---------------------------------------------------------------------------*/
00274 unsigned char
00275 ctk_mode_get(void) {
00276   return mode;
00277 }
00278 /*---------------------------------------------------------------------------*/
00279 /**
00280  * Add an icon to the desktop.
00281  *
00282  * \param icon The icon to be added.
00283  *
00284  * \param p The process that owns the icon.
00285  */
00286 /*---------------------------------------------------------------------------*/
00287 void
00288 ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, struct process *p)
00289 {
00290 #if CTK_CONF_ICONS
00291   /*  icon->x = iconx;
00292   icon->y = icony;
00293   icon->widget.icon.owner = id;
00294 
00295   icony += ICONY_DELTA;
00296   if(icony >= ICONY_MAX) {
00297     icony = ICONY_START;
00298     iconx += ICONX_DELTA;
00299     }*/
00300   icon->widget.icon.owner = p;
00301   ctk_widget_add(&desktop_window, icon);
00302   arrange_icons();
00303 #endif /* CTK_CONF_ICONS */
00304 }
00305 /*---------------------------------------------------------------------------*/
00306 /**
00307  * Open a dialog box.
00308  *
00309  * \param d The dialog to be opened.
00310  */
00311 /*---------------------------------------------------------------------------*/
00312 void
00313 ctk_dialog_open(struct ctk_window *d)
00314 {
00315   dialog = d;
00316   redraw |= REDRAW_FOCUS;
00317 }
00318 /*---------------------------------------------------------------------------*/
00319 /**
00320  * Close the dialog box, if one is open.
00321  *
00322  */
00323 /*---------------------------------------------------------------------------*/
00324 void
00325 ctk_dialog_close(void)
00326 {
00327   dialog = NULL;
00328   redraw |= REDRAW_ALL;
00329 }
00330 /*---------------------------------------------------------------------------*/
00331 /**
00332  * Open a window, or bring window to front if already open.
00333  *
00334  * \param w The window to be opened.
00335  */
00336 /*---------------------------------------------------------------------------*/
00337 void
00338 ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
00339 {
00340   struct ctk_window *w2;
00341   
00342   /* Check if already open. */
00343   for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
00344   if(w2 == NULL) {
00345    /* Not open, so we add it at the head of the list of open
00346        windows. */
00347     w->next = windows;
00348     if(windows != NULL) {
00349       windows->prev = w;
00350     }
00351     windows = w;
00352     w->prev = NULL;
00353   } else {
00354     /* Window already open, so we move it to the front of the windows
00355        list. */
00356     if(w != windows) {
00357       if(w->next != NULL) {
00358         w->next->prev = w->prev;
00359       }
00360       if(w->prev != NULL) {
00361         w->prev->next = w->next;
00362       }
00363       w->next = windows;
00364       windows->prev = w;
00365       windows = w;
00366       w->prev = NULL;
00367     }
00368   }
00369   
00370 #if CTK_CONF_MENUS
00371   /* Recreate the Desktop menu's window entries.*/
00372   make_desktopmenu();
00373 #endif /* CTK_CONF_MENUS */
00374 
00375   redraw |= REDRAW_ALL;
00376 }
00377 /*---------------------------------------------------------------------------*/
00378 /**
00379  * Close a window if it is open.
00380  *
00381  * If the window is not open, this function does nothing.
00382  *
00383  * \param w The window to be closed.
00384  */
00385 /*---------------------------------------------------------------------------*/
00386 void
00387 ctk_window_close(struct ctk_window *w)
00388 {
00389   static struct ctk_window *w2;
00390 
00391   if(w == NULL) {
00392     return;
00393   }
00394   
00395   /* Check if the window to be closed is the first window on the
00396      list. */
00397   if(w == windows) {
00398     windows = w->next;
00399     if(windows != NULL) {
00400       windows->prev = NULL;
00401     }
00402     w->next = w->prev = NULL;
00403   } else {
00404     /* Otherwise we step through the list until we find the window
00405        before the one to be closed. We then redirect its ->next
00406        pointer and its ->next->prev. */
00407     for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
00408 
00409     if(w2 == NULL) {
00410       /* The window wasn't open, so there is nothing more for us to
00411          do. */
00412       return;
00413     }
00414 
00415     if(w->next != NULL) {
00416       w->next->prev = w->prev;
00417     }
00418     w2->next = w->next;
00419     
00420     w->next = w->prev = NULL;
00421   }
00422   
00423 #if CTK_CONF_MENUS
00424   /* Recreate the Desktop menu's window entries.*/
00425   make_desktopmenu();
00426 #endif /* CTK_CONF_MENUS */
00427   redraw |= REDRAW_ALL;
00428 }
00429 /*---------------------------------------------------------------------------*/
00430 /**
00431  * \internal Create the move and close buttons on the window titlebar.
00432  */
00433 /*---------------------------------------------------------------------------*/
00434 static void
00435 make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
00436 {
00437   unsigned char placement;
00438 
00439   if(ctk_draw_windowtitle_height >= 2) {
00440     placement = -1 - ctk_draw_windowtitle_height/2;
00441   } else {
00442     placement = -1;
00443   }
00444 #if CTK_CONF_WINDOWMOVE
00445   CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
00446                  window->titlelen, window->title);
00447 #else
00448   CTK_LABEL_NEW(&window->titlebutton, 0, placement,
00449                 window->titlelen, 1, window->title);
00450 #endif /* CTK_CONF_WINDOWMOVE */
00451   CTK_WIDGET_ADD(window, &window->titlebutton);
00452 
00453 
00454 #if CTK_CONF_WINDOWCLOSE
00455   CTK_BUTTON_NEW(&window->closebutton, window->w - 3, placement,
00456                  1, "x");
00457 #else
00458   CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
00459                 3, 1, "   ");
00460 #endif /* CTK_CONF_WINDOWCLOSE */
00461   CTK_WIDGET_ADD(window, &window->closebutton);
00462 }
00463 /*---------------------------------------------------------------------------*/
00464 /**
00465  * Remove all widgets from a window.
00466  *
00467  * \param w The window to be cleared.
00468  */
00469 /*---------------------------------------------------------------------------*/
00470 void
00471 ctk_window_clear(struct ctk_window *w)
00472 {
00473   w->active = w->inactive = w->focused = NULL;
00474   
00475   make_windowbuttons(w);
00476 }
00477 /*---------------------------------------------------------------------------*/
00478 /**
00479  * Add a menu to the menu bar.
00480  *
00481  * \param menu The menu to be added.
00482  *
00483  * \note Do not call this function multiple times for the same menu,
00484  * as no check is made to see if the menu already is in the menu bar.
00485  */
00486 /*---------------------------------------------------------------------------*/
00487 void
00488 ctk_menu_add(struct ctk_menu *menu)
00489 {
00490 #if CTK_CONF_MENUS
00491   struct ctk_menu *m;
00492 
00493   if(lastmenu == NULL) {
00494     lastmenu = menu;
00495   }
00496     
00497   for(m = menus.menus; m->next != NULL; m = m->next) {
00498     if(m == menu) {
00499       return;
00500     }
00501   }
00502   m->next = menu;
00503   menu->next = NULL;
00504 
00505   redraw |= REDRAW_MENUPART;
00506 #endif /* CTK_CONF_MENUS */
00507 }
00508 /*---------------------------------------------------------------------------*/
00509 /**
00510  * Remove a menu from the menu bar.
00511  *
00512  * \param menu The menu to be removed.
00513  */
00514 /*---------------------------------------------------------------------------*/
00515 void
00516 ctk_menu_remove(struct ctk_menu *menu)
00517 {
00518 #if CTK_CONF_MENUS
00519   struct ctk_menu *m;
00520 
00521   for(m = menus.menus; m->next != NULL; m = m->next) {
00522     if(m->next == menu) {
00523       m->next = menu->next;
00524       if(menu == lastmenu) {
00525         lastmenu = NULL;
00526       }
00527       redraw |= REDRAW_MENUPART;
00528       return;
00529     }
00530   }
00531 #endif /* CTK_CONF_MENUS */
00532 }
00533 /*---------------------------------------------------------------------------*/
00534 /**
00535  * \internal Redraws everything on the screen within the clip
00536  * interval.
00537  *
00538  * \param clipy1 The upper bound of the clip interval
00539  * \param clipy2 The lower bound of the clip interval
00540  */
00541 /*---------------------------------------------------------------------------*/
00542 static void CC_FASTCALL
00543 do_redraw_all(unsigned char clipy1, unsigned char clipy2)
00544 {
00545   struct ctk_window *w;
00546   static struct ctk_widget *widget;
00547   unsigned char focus;
00548 
00549   if(mode != CTK_MODE_NORMAL &&
00550      mode != CTK_MODE_WINDOWMOVE) {
00551     return;
00552   }
00553   
00554   ctk_draw_clear(clipy1, clipy2);
00555 
00556   /* Draw widgets in root window */
00557   for(widget = desktop_window.active;
00558       widget != NULL; widget = widget->next) {
00559     ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
00560   }
00561   
00562   /* Draw windows */
00563   if(windows != NULL) {
00564     /* Find the last window.*/
00565     for(w = windows; w->next != NULL; w = w->next);
00566 
00567     /* Draw the windows from back to front. */
00568     for(; w != windows; w = w->prev) {
00569       ctk_draw_clear_window(w, 0, clipy1, clipy2);
00570       ctk_draw_window(w, 0, clipy1, clipy2, 1);
00571     }
00572 
00573     /* Draw focused window */
00574     focus = mode == CTK_MODE_WINDOWMOVE?
00575             CTK_FOCUS_WIDGET|CTK_FOCUS_WINDOW:
00576             CTK_FOCUS_WINDOW;
00577     ctk_draw_clear_window(windows, focus, clipy1, clipy2);
00578     ctk_draw_window(windows, focus, clipy1, clipy2, 1);
00579   }
00580 
00581   /* Draw dialog (if any) */
00582   if(dialog != NULL) {
00583     ctk_draw_dialog(dialog);
00584   }
00585 
00586 #if CTK_CONF_MENUS
00587   ctk_draw_menus(&menus);
00588 #endif /* CTK_CONF_MENUS */
00589 }
00590 /*---------------------------------------------------------------------------*/
00591 /**
00592  * Redraw the entire desktop.
00593  *
00594  * \param d The desktop to be redrawn.
00595  *
00596  * \note Currently the parameter d is not used, but must be set to
00597  * NULL.
00598  *
00599  */
00600 /*---------------------------------------------------------------------------*/
00601 void
00602 ctk_desktop_redraw(struct ctk_desktop *d)
00603 {
00604   if(PROCESS_CURRENT() == &ctk_process) {
00605     if(mode == CTK_MODE_NORMAL ||
00606        mode == CTK_MODE_WINDOWMOVE) {
00607       
00608       do_redraw_all(1, height);
00609     }
00610   } else {
00611     height = ctk_draw_height();
00612     width = ctk_draw_width();
00613     
00614     redraw |= REDRAW_ALL;
00615   }
00616 }
00617 /*---------------------------------------------------------------------------*/
00618 /**
00619  * Redraw a window.
00620  *
00621  * This function redraws the window, but only if it is the foremost
00622  * one on the desktop.
00623  *
00624  * \param w The window to be redrawn.
00625  */
00626 /*---------------------------------------------------------------------------*/
00627 void
00628 ctk_window_redraw(struct ctk_window *w)
00629 {
00630   /* Only redraw the window if it is a dialog or if it is the foremost
00631      window. */
00632   if(mode != CTK_MODE_NORMAL) {
00633     return;
00634   }
00635   
00636   if(w == dialog) {
00637     ctk_draw_dialog(w);
00638   } else if(dialog == NULL &&
00639 #if CTK_CONF_MENUS
00640             menus.open == NULL &&
00641 #endif /* CTK_CONF_MENUS */
00642             windows == w) {
00643     ctk_draw_window(w, CTK_FOCUS_WINDOW,
00644                     0, height, 0);
00645   }
00646 }
00647 /*---------------------------------------------------------------------------*/
00648 /**
00649  * \internal Creates a new window.
00650  *
00651  * \param window The window to be created.
00652  * \param w The width of the window.
00653  * \param h The height of the window.
00654  * \param title The title of the window.
00655  */
00656 /*---------------------------------------------------------------------------*/
00657 static void
00658 window_new(CC_REGISTER_ARG struct ctk_window *window,
00659            unsigned char w, unsigned char h,
00660            char *title)
00661 {
00662   
00663   if(w >= width - 2) {
00664     window->x = 0;
00665   } else {
00666     window->x = (width - w - 2) / 2;
00667   }
00668   if(h >= height - 2 - ctk_draw_windowtitle_height) {
00669     window->y = 0;
00670   } else {
00671     window->y = (height - h - 2 - ctk_draw_windowtitle_height) / 2;
00672   }
00673 
00674   window->w = w;
00675   window->h = h;
00676   window->title = title;
00677   if(title != NULL) {
00678     window->titlelen = strlen(title);
00679   } else {
00680     window->titlelen = 0;
00681   }
00682   window->next = window->prev = NULL;
00683   /*  window->owner = DISPATCHER_CURRENT();*/
00684   window->owner = PROCESS_CURRENT();
00685   window->active = window->inactive = window->focused = NULL;
00686 }
00687 /*---------------------------------------------------------------------------*/
00688 /**
00689  * Create a new window.
00690  *
00691  * Creates a new window. The memory for the window structure must
00692  * already be allocated by the caller, and is usually done with a
00693  * static declaration.
00694  *
00695  * This function sets up the internal structure of the ctk_window
00696  * struct and creates the move and close buttons, but it does not open
00697  * the window. The window must be explicitly opened by calling the
00698  * ctk_window_open() function.
00699  *
00700  * \param window The window to be created.
00701  * \param w The width of the new window.
00702  * \param h The height of the new window.
00703  * \param title The title of the new window.
00704  */
00705 /*---------------------------------------------------------------------------*/
00706 void
00707 ctk_window_new(struct ctk_window *window,
00708                unsigned char w, unsigned char h,
00709                char *title)
00710 {
00711   window_new(window, w, h, title);
00712 
00713   make_windowbuttons(window);
00714 }
00715 /*---------------------------------------------------------------------------*/
00716 /**
00717  * Creates a new dialog.
00718  *
00719  * This function only sets up the internal structure of the ctk_window
00720  * struct but does not open the dialog. The dialog must be explicitly
00721  * opened by calling the ctk_dialog_open() function.
00722  *
00723  * \param dialog The dialog to be created.
00724  * \param w The width of the dialog.
00725  * \param h The height of the dialog.
00726  */
00727 /*---------------------------------------------------------------------------*/
00728 void
00729 ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
00730                unsigned char w, unsigned char h)
00731 {
00732   window_new(dialog, w, h, NULL);
00733 }
00734 /*---------------------------------------------------------------------------*/
00735 /**
00736  * Creates a new menu.
00737  *
00738  * This function sets up the internal structure of the menu, but does
00739  * not add it to the menubar. Use the function ctk_menu_add() for that
00740  * purpose.
00741  *
00742  * \param menu The menu to be created.
00743  * \param title The title of the menu.
00744  */
00745 /*---------------------------------------------------------------------------*/
00746 void
00747 ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
00748              char *title)
00749 {
00750 #if CTK_CONF_MENUS
00751   menu->next = NULL;
00752   menu->title = title;
00753   menu->titlelen = strlen(title);
00754   menu->active = 0;
00755   menu->nitems = 0;
00756 #endif /* CTK_CONF_MENUS */
00757 }
00758 /*---------------------------------------------------------------------------*/
00759 /**
00760  * Adds a menu item to a menu.
00761  *
00762  * In CTK, each menu item is identified by a number which is unique
00763  * within each menu. When a menu item is selected, a
00764  * ctk_menuitem_activated signal is emitted and the menu item number
00765  * is passed as signal data with the signal.
00766  *
00767  * \param menu The menu to which the menu item should be added.
00768  * \param name The name of the menu item.
00769  * \return The number of the menu item.
00770  */
00771 /*---------------------------------------------------------------------------*/
00772 unsigned char
00773 ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
00774                  char *name)
00775 {
00776 #if CTK_CONF_MENUS
00777   if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
00778     return 0;
00779   }
00780   menu->items[menu->nitems].title = name;
00781   menu->items[menu->nitems].titlelen = strlen(name);
00782   return menu->nitems++;
00783 #else
00784   return 0;
00785 #endif /* CTK_CONF_MENUS */
00786 }
00787 /*---------------------------------------------------------------------------*/
00788 /**
00789  * \internal Adds a widget to the list of widgets that should be
00790  * redrawn.
00791  *
00792  * \param w The widget that should be redrawn.
00793  */
00794 /*---------------------------------------------------------------------------*/
00795 static void CC_FASTCALL
00796 add_redrawwidget(struct ctk_widget *w)
00797 {
00798   static unsigned char i;
00799   
00800   if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
00801     redraw |= REDRAW_FOCUS;
00802   } else {
00803     redraw |= REDRAW_WIDGETS;
00804     /* Check if it is in the queue already. If so, we don't add it
00805        again. */
00806     for(i = 0; i < redraw_widgetptr; ++i) {
00807       if(redraw_widgets[i] == w) {
00808         return;
00809       }
00810     }
00811     redraw_widgets[redraw_widgetptr++] = w;
00812   }
00813 }
00814 /*---------------------------------------------------------------------------*/
00815 /**
00816  * \internal Checks if a widget redrawn and adds it to the list of
00817  * widgets to be redrawn.
00818  *
00819  * A widget can be redrawn only if the current CTK mode is
00820  * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
00821  * foremost window.
00822  *
00823  * \param widget The widget that should be redrawn.
00824  */
00825 /*---------------------------------------------------------------------------*/
00826 static void
00827 widget_redraw(struct ctk_widget *widget)
00828 {
00829   struct ctk_window *window;
00830 
00831   if(mode != CTK_MODE_NORMAL || widget == NULL) {
00832     return;
00833   }
00834 
00835   /* Only redraw widgets that are in the foremost window. If we would
00836      allow redrawing widgets in non-focused windows, we would have to
00837      redraw all the windows that cover the non-focused window as well,
00838      which would lead to flickering.
00839 
00840      Also, we avoid drawing any widgets when the menus are active.
00841     */
00842     
00843 #if CTK_CONF_MENUS
00844   if(menus.open == NULL)
00845 #endif /* CTK_CONF_MENUS */
00846     {
00847       window = widget->window;
00848       if(window == dialog) {
00849         ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
00850       } else if(dialog == NULL &&
00851                 (window == windows ||
00852                  window == &desktop_window)) {
00853         ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
00854       }
00855     }
00856 }
00857 /*---------------------------------------------------------------------------*/
00858 /**
00859  * Redraws a widget.
00860  *
00861  * This function will set a flag which causes the widget to be redrawn
00862  * next time the CTK process is scheduled.
00863  *
00864  * \param widget The widget that is to be redrawn.
00865  *
00866  * \note This function should usually not be called directly since it
00867  * requires typecasting of the widget parameter. The wrapper macro
00868  * CTK_WIDGET_REDRAW() does the required typecast and should be used
00869  * instead.
00870  */
00871 /*---------------------------------------------------------------------------*/
00872 void
00873 ctk_widget_redraw(struct ctk_widget *widget)
00874 {
00875   if(mode != CTK_MODE_NORMAL || widget == NULL) {
00876     return;
00877   }
00878 
00879   /* Since this function isn't called by CTK itself, we only queue the
00880      redraw request. */
00881   add_redrawwidget(widget);
00882 }
00883 /*---------------------------------------------------------------------------*/
00884 /**
00885  * Adds a widget to a window.
00886  *
00887  * This function adds a widget to a window. The order of which the
00888  * widgets are added is important, as it sets the order to which
00889  * widgets are cycled with the widget selection keys.
00890  *
00891  * \param window The window to which the widhet should be added.
00892  * \param widget The widget to be added.
00893  */
00894 /*---------------------------------------------------------------------------*/
00895 void CC_FASTCALL
00896 ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
00897                CC_REGISTER_ARG struct ctk_widget *widget)
00898 {
00899   if(widget->type == CTK_WIDGET_LABEL ||
00900      widget->type == CTK_WIDGET_SEPARATOR) {
00901     widget->next = window->inactive;
00902     window->inactive = widget;
00903     widget->window = window;
00904   } else {
00905     widget->next = window->active;
00906     window->active = widget;
00907     widget->window = window;
00908     /*    if(window->focused == NULL) {
00909       window->focused = widget;
00910       }*/
00911   }
00912 }
00913 /*---------------------------------------------------------------------------*/
00914 /**
00915  * Gets the width of the desktop.
00916  *
00917  * \param d The desktop.
00918  * \return The width of the desktop, in characters.
00919  *
00920  * \note The d parameter is currently unused and must be set to NULL.
00921  */
00922 /*---------------------------------------------------------------------------*/
00923 unsigned char
00924 ctk_desktop_width(struct ctk_desktop *d)
00925 {
00926   return ctk_draw_width();
00927 }
00928 /*---------------------------------------------------------------------------*/
00929 /**
00930  * Gets the height of the desktop.
00931  *
00932  * \param d The desktop.
00933  * \return The height of the desktop, in characters.
00934  *
00935  * \note The d parameter is currently unused and must be set to NULL.
00936  */
00937 /*---------------------------------------------------------------------------*/
00938 unsigned char
00939 ctk_desktop_height(struct ctk_desktop *d)
00940 {
00941   return ctk_draw_height();
00942 }
00943 /*---------------------------------------------------------------------------*/
00944 /**
00945  * \internal Selects a widget in the window of the widget.
00946  *
00947  * \param focus The widget to be focused.
00948  */
00949 /*---------------------------------------------------------------------------*/
00950 static void CC_FASTCALL
00951 select_widget(struct ctk_widget *focus)
00952 {
00953   struct ctk_window *window;
00954 
00955   window = focus->window;
00956   
00957   if(focus != window->focused) {
00958     window->focused = focus;
00959     /* The operation changed the focus, so we emit a "hover" signal
00960        for those widgets that support it. */
00961     
00962     if(window->focused->type == CTK_WIDGET_HYPERLINK) {
00963       process_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
00964     } else if(window->focused->type == CTK_WIDGET_BUTTON) {
00965       process_post(window->owner, ctk_signal_button_hover, window->focused);
00966     }
00967     
00968     add_redrawwidget(window->focused);
00969 
00970     process_post(focus->window->owner, ctk_signal_widget_select, focus);
00971 
00972   }
00973 
00974 }
00975 /*---------------------------------------------------------------------------*/
00976 #define UP 0
00977 #define DOWN 1
00978 #define LEFT 2
00979 #define RIGHT 3
00980 static void CC_FASTCALL
00981 switch_focus_widget(unsigned char direction)
00982 {
00983   register struct ctk_window *window;
00984   register struct ctk_widget *focus;
00985   struct ctk_widget *widget;
00986   
00987   
00988   if(dialog != NULL) {
00989     window = dialog;
00990   } else {
00991     window = windows;
00992   }
00993 
00994   /* If there are no windows open, we move focus around between the
00995      icons on the root window instead. */
00996   if(window == NULL) {
00997     window = &desktop_window;
00998   }
00999  
01000   focus = window->focused;
01001   if(focus == NULL) {
01002     focus = window->active;
01003     if(focus == NULL) {
01004       return;
01005     }
01006   }
01007   add_redrawwidget(focus);
01008   
01009   if((direction & 1) == 0) {
01010     /* Move focus "up" */
01011     focus = focus->next;
01012   } else {
01013     /* Move focus "down" */
01014     for(widget = window->active;
01015         widget != NULL; widget = widget->next) {
01016         if(widget->next == focus) {
01017           break;
01018         }
01019     }
01020     focus = widget;
01021     if(focus == NULL) {
01022       if(window->active != NULL) {
01023         for(focus = window->active;
01024             focus->next != NULL; focus = focus->next);
01025       }
01026     }
01027   }
01028   if(focus == NULL) {
01029     focus = window->active;
01030   }
01031 
01032   select_widget(focus);
01033 }
01034 /*---------------------------------------------------------------------------*/
01035 #if CTK_CONF_MENUS
01036 static void
01037 switch_open_menu(unsigned char rightleft)
01038 {
01039   struct ctk_menu *menu;
01040   
01041   if(rightleft == 0) {
01042     /* Move right */
01043     for(menu = menus.menus; menu != NULL; menu = menu->next) {
01044       if(menu->next == menus.open) {
01045         break;
01046       }
01047     }
01048     lastmenu = menus.open;
01049     menus.open = menu;
01050     if(menus.open == NULL) {
01051       for(menu = menus.menus;
01052           menu->next != NULL; menu = menu->next);
01053       menus.open = menu;
01054     }
01055   } else {
01056     /* Move to left */
01057     lastmenu = menus.open;
01058     menus.open = menus.open->next;
01059     if(menus.open == NULL) {
01060       menus.open = menus.menus;
01061     }
01062   }
01063 
01064   menus.open->active = 0;
01065 
01066   /*  if(menus.open->nitems > maxnitems) {
01067     maxnitems = menus.open->nitems;
01068     }*/
01069 
01070   /*  ctk_desktop_redraw();*/
01071 }
01072 /*---------------------------------------------------------------------------*/
01073 static void
01074 switch_menu_item(unsigned char updown)
01075 {
01076   register struct ctk_menu *m;
01077 
01078   m = menus.open;
01079   
01080   if(updown == 0) {
01081     /* Move up */
01082     if(m->active == 0) {
01083       m->active = m->nitems - 1;
01084     } else {
01085       --m->active;
01086       if(m->items[m->active].title[0] == '-') {
01087         --m->active;
01088       }
01089     }
01090   } else {
01091     /* Move down */
01092     if(m->active >= m->nitems - 1) {
01093       m->active = 0;
01094     } else {
01095       ++m->active;
01096       if(m->items[m->active].title[0] == '-') {
01097         ++m->active;
01098       }
01099     }
01100   }
01101   
01102 }
01103 #endif /* CTK_CONF_MENUS */
01104 /*---------------------------------------------------------------------------*/
01105 static unsigned char CC_FASTCALL
01106 activate(CC_REGISTER_ARG struct ctk_widget *w)
01107 {
01108   if(w->type == CTK_WIDGET_BUTTON) {
01109     if(w == (struct ctk_widget *)&windows->closebutton) {
01110 #if CTK_CONF_WINDOWCLOSE
01111       process_post(w->window->owner, ctk_signal_window_close, windows);
01112       ctk_window_close(windows);
01113       return REDRAW_ALL;
01114 #endif /* CTK_CONF_WINDOWCLOSE */
01115     } else if(w == (struct ctk_widget *)&windows->titlebutton) {
01116 #if CTK_CONF_WINDOWMOVE
01117       mode = CTK_MODE_WINDOWMOVE;
01118       return REDRAW_ALL;
01119 #endif /* CTK_CONF_WINDOWMOVE */
01120     } else {
01121       process_post(w->window->owner, ctk_signal_widget_activate, w);
01122     }
01123 #if CTK_CONF_ICONS
01124   } else if(w->type == CTK_WIDGET_ICON) {
01125     if(w->widget.icon.owner != PROCESS_NONE) {
01126       process_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
01127     } else {
01128       process_post(w->window->owner, ctk_signal_widget_activate, w);
01129     }
01130 #endif /* CTK_CONF_ICONS */
01131   } else if(w->type == CTK_WIDGET_HYPERLINK) {
01132     process_post(PROCESS_BROADCAST, ctk_signal_hyperlink_activate, w);
01133   } else if(w->type == CTK_WIDGET_TEXTENTRY) {
01134     if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
01135       w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
01136       textentry_input(0, (struct ctk_textentry *)w);
01137     } else {
01138       w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
01139       process_post(w->window->owner, ctk_signal_widget_activate, w);
01140     }
01141     add_redrawwidget(w);
01142     return REDRAW_WIDGETS;
01143   } else {
01144     process_post(w->window->owner, ctk_signal_widget_activate, w);
01145   }
01146   return REDRAW_NONE;
01147 }
01148 /*---------------------------------------------------------------------------*/
01149 static void CC_FASTCALL
01150 textentry_input(ctk_arch_key_t c,
01151                 CC_REGISTER_ARG struct ctk_textentry *t)
01152 {
01153   register char *cptr, *cptr2;
01154   static unsigned char len, txpos, typos, tlen;
01155 
01156   if(t->input != NULL && t->input(c, t)) {
01157     return;
01158   }
01159 
01160   txpos = t->xpos;
01161   typos = t->ypos;
01162   tlen = t->len;
01163 
01164   cptr = &t->text[txpos + typos * (tlen + 1)];
01165       
01166   switch(c) {
01167   case CH_CURS_LEFT:
01168     if(txpos > 0) {
01169       --txpos;
01170     }
01171     break;
01172     
01173   case CH_CURS_RIGHT:
01174     if(txpos < tlen - 1 && *cptr != 0) {
01175       ++txpos;
01176     }
01177     break;
01178 
01179   case CH_CURS_UP:
01180     txpos = 0;
01181     break;
01182     
01183   case 0:
01184   case CH_CURS_DOWN:
01185     txpos = strlen(t->text);
01186     if(txpos == tlen) {
01187       --txpos;
01188     }
01189     break;
01190     
01191   case CH_ENTER:
01192     /*    t->state = CTK_TEXTENTRY_NORMAL;*/
01193     activate((struct ctk_widget *)t);
01194     switch_focus_widget(DOWN);
01195     break;
01196     
01197   case CTK_CONF_WIDGETDOWN_KEY:
01198     t->state = CTK_TEXTENTRY_NORMAL;
01199     switch_focus_widget(DOWN);
01200     break;
01201   case CTK_CONF_WIDGETUP_KEY:
01202     t->state = CTK_TEXTENTRY_NORMAL;
01203     switch_focus_widget(UP);
01204     break;
01205     
01206   default:
01207     len = tlen - txpos;
01208     if(c == CH_DEL) {
01209       if(len == 1 && *cptr != 0) {
01210         *cptr = 0;
01211       } else {
01212         if(txpos > 0) {
01213           --txpos;
01214           strcpy(cptr - 1, cptr);
01215         }
01216       }
01217     } else {
01218       if(ctk_arch_isprint(c)) {
01219         if(len > 1) {
01220           cptr2 = cptr + len - 1;
01221           while(cptr2 > cptr) {
01222             *cptr2 = *(cptr2 - 1);
01223             --cptr2;
01224           }
01225           ++txpos;
01226         }
01227         *cptr = c;
01228       }
01229     }
01230     break;
01231   }
01232 
01233   t->xpos = txpos;
01234   t->ypos = typos;
01235 }
01236 /*---------------------------------------------------------------------------*/
01237 #if CTK_CONF_MENUS
01238 static unsigned char
01239 activate_menu(void)
01240 {
01241   struct ctk_window *w;
01242   
01243   lastmenu = menus.open;
01244   if(menus.open == &desktopmenu) {
01245     for(w = windows; w != NULL; w = w->next) {
01246       if(w->title == desktopmenu.items[desktopmenu.active].title) {
01247         ctk_window_open(w);
01248         menus.open = NULL;
01249         return REDRAW_ALL;
01250       }
01251     }
01252   } else {
01253     process_post(PROCESS_BROADCAST, ctk_signal_menu_activate, menus.open);
01254   }
01255   menus.open = NULL;
01256   return REDRAW_MENUPART;
01257 }
01258 /*---------------------------------------------------------------------------*/
01259 static unsigned char
01260 menus_input(ctk_arch_key_t c)
01261 {
01262 
01263   if(menus.open->nitems > maxnitems) {
01264     maxnitems = menus.open->nitems;
01265   }
01266 
01267   
01268   switch(c) {
01269   case CH_CURS_RIGHT:
01270     switch_open_menu(1);
01271         
01272     return REDRAW_MENUPART;
01273 
01274   case CH_CURS_DOWN:
01275     switch_menu_item(1);
01276     return REDRAW_MENUS;
01277 
01278   case CH_CURS_LEFT:
01279     switch_open_menu(0);
01280     return REDRAW_MENUPART;
01281 
01282   case CH_CURS_UP:
01283     switch_menu_item(0);
01284     return REDRAW_MENUS;
01285     
01286   case CH_ENTER:
01287     return activate_menu();
01288 
01289   case CTK_CONF_MENU_KEY:
01290     lastmenu = menus.open;
01291     menus.open = NULL;
01292     return REDRAW_MENUPART;
01293   }
01294 
01295   return REDRAW_NONE;
01296 }
01297 #endif /* CTK_CONF_MENUS */
01298 /*---------------------------------------------------------------------------*/
01299 static void
01300 handle_timer(void)
01301 {
01302   if(mode == CTK_MODE_NORMAL) {
01303     ++screensaver_timer;
01304     if(screensaver_timer >= ctk_screensaver_timeout) {
01305 #if CTK_CONF_SCREENSAVER
01306       process_post(PROCESS_BROADCAST, ctk_signal_screensaver_start, NULL);
01307 #ifdef CTK_SCREENSAVER_INIT
01308       CTK_SCREENSAVER_INIT();
01309 #endif /* CTK_SCREENSAVER_INIT */
01310 
01311 #endif /* CTK_CONF_SCREENSAVER */
01312       screensaver_timer = 0;
01313     }
01314   }
01315 }
01316 /*---------------------------------------------------------------------------*/
01317 static void
01318 unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
01319 {
01320   if(w != NULL) {
01321     redraw |= REDRAW_WIDGETS;
01322     add_redrawwidget(w);
01323     if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
01324       ((struct ctk_textentry *)w)->state =
01325         CTK_TEXTENTRY_NORMAL;
01326     }
01327     w->window->focused = NULL;
01328   }
01329 }
01330 /*---------------------------------------------------------------------------*/
01331 PROCESS_THREAD(ctk_process, ev, data)
01332 {
01333   static ctk_arch_key_t c;
01334   static unsigned char i;
01335   register struct ctk_window *window;
01336   register struct ctk_widget *widget;
01337   register struct ctk_widget **widgetptr;
01338 #if CTK_CONF_MOUSE_SUPPORT
01339   static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
01340     mouse_clicked;
01341   static unsigned char menux;
01342   register struct ctk_menu *menu;
01343 
01344 #endif /* CTK_CONF_MOUSE_SUPPORT */
01345 
01346   
01347   PROCESS_BEGIN();
01348   
01349   windows = NULL;
01350   dialog = NULL;
01351 
01352 #if CTK_CONF_MENUS
01353   ctk_menu_new(&desktopmenu, "Desktop");
01354   make_desktopmenu();
01355   menus.menus = menus.desktopmenu = &desktopmenu;
01356 #endif /* CTK_CONF_MENUS */
01357 
01358 #if CTK_CONF_MOUSE_SUPPORT
01359   ctk_mouse_init();
01360   ctk_mouse_show();
01361 #endif /* CTK_CONF_MOUSE_SUPPORT */
01362   
01363   ctk_draw_init();
01364 
01365   height = ctk_draw_height();
01366   width = ctk_draw_width();
01367   
01368   desktop_window.active = NULL;
01369   desktop_window.owner = &ctk_process;
01370   
01371   ctk_signal_keypress = process_alloc_event();
01372   
01373   ctk_signal_button_activate =
01374     ctk_signal_widget_activate = process_alloc_event();
01375   
01376   ctk_signal_button_hover =
01377     ctk_signal_hyperlink_hover =
01378     ctk_signal_widget_select = process_alloc_event();
01379   
01380   ctk_signal_hyperlink_activate = process_alloc_event();
01381 
01382   ctk_signal_menu_activate = process_alloc_event();
01383   ctk_signal_window_close = process_alloc_event();
01384 
01385   ctk_signal_pointer_move = process_alloc_event();
01386   ctk_signal_pointer_button = process_alloc_event();
01387 
01388 
01389 #if CTK_CONF_SCREENSAVER
01390   ctk_signal_screensaver_start = process_alloc_event();
01391   ctk_signal_screensaver_stop = process_alloc_event();
01392 #endif /* CTK_CONF_SCREENSAVER */
01393     
01394 
01395   mode = CTK_MODE_NORMAL;
01396 
01397   iconx = ICONX_START;
01398   icony = ICONY_START;
01399 
01400   redraw = REDRAW_ALL;
01401 
01402   timer_set(&timer, CLOCK_SECOND);
01403   
01404   while(1) {
01405     process_poll(&ctk_process);
01406     PROCESS_WAIT_EVENT();
01407     
01408     if(timer_expired(&timer)) {
01409       timer_reset(&timer);
01410       handle_timer();
01411     }
01412 
01413 #if CTK_CONF_MENUS
01414     if(menus.open != NULL) {
01415       maxnitems = menus.open->nitems;
01416     } else {
01417       maxnitems = 0;
01418     }
01419 #endif /* CTK_CONF_MENUS */
01420 
01421 #if CTK_CONF_MOUSE_SUPPORT
01422     mouse_button_changed = mouse_moved = mouse_clicked = 0;
01423 
01424     /* See if there is any change in the buttons. */
01425     if(ctk_mouse_button() != mouse_button) {
01426       mouse_button = ctk_mouse_button();
01427       mouse_button_changed = 1;
01428       if(mouse_button == 0) {
01429         mouse_clicked = 1;
01430       }
01431     }
01432   
01433     /* Check if the mouse pointer has moved. */
01434     if(ctk_mouse_x() != mouse_x ||
01435        ctk_mouse_y() != mouse_y) {
01436       mouse_x = ctk_mouse_x();
01437       mouse_y = ctk_mouse_y();
01438       mouse_moved = 1;
01439     }
01440 
01441     mxc = ctk_mouse_xtoc(mouse_x);
01442     myc = ctk_mouse_ytoc(mouse_y);
01443 #endif /* CTK_CONF_MOUSE_SUPPORT */
01444 
01445 
01446 #if CTK_CONF_SCREENSAVER
01447     if(mode == CTK_MODE_SCREENSAVER) {
01448       if(ctk_arch_keyavail()
01449 #if CTK_CONF_MOUSE_SUPPORT
01450          || mouse_moved || mouse_button_changed
01451 #endif /* CTK_CONF_MOUSE_SUPPORT */
01452          ) {
01453         process_post(PROCESS_BROADCAST, ctk_signal_screensaver_stop, NULL);
01454         mode = CTK_MODE_NORMAL;
01455       }
01456     } else
01457 #endif /* CTK_CONF_SCREENSAVER */
01458       if(mode == CTK_MODE_NORMAL) {
01459 #if CTK_CONF_MOUSE_SUPPORT
01460         /* If there is any change in the mouse conditions, find out in
01461            which window the mouse pointer currently is in order to send
01462            the correct signals, or bring a window to focus. */
01463         if(mouse_moved || mouse_button_changed) {
01464           ctk_mouse_show();
01465           screensaver_timer = 0;
01466       
01467           if(myc == 0) {
01468             /* Here we should do whatever needs to be done when the mouse
01469                moves around and clicks in the menubar. */
01470             if(mouse_clicked) {
01471               static unsigned char titlelen;
01472           
01473               /* Find out which menu that the mouse pointer is in. Start
01474                  with the ->next menu after the desktop menu. We assume
01475                  that the menus start one character from the left screen
01476                  side and that the desktop menu is farthest to the
01477                  right. */
01478               menux = 1;
01479               for(menu = menus.menus->next;
01480                   menu != NULL; menu = menu->next) {
01481                 titlelen = menu->titlelen;
01482                 if(mxc >= menux && mxc <= menux + titlelen) {
01483                   break;
01484                 }
01485                 menux += titlelen;
01486               }
01487           
01488               /* Also check desktop menu. */
01489               if(mxc >= width - 7 &&
01490                  mxc <= width - 1) {
01491                 menu = &desktopmenu;
01492               }
01493           
01494               menus.open = menu;
01495               redraw |= REDRAW_MENUPART;
01496             }
01497           } else {
01498             --myc;
01499 
01500             if(menus.open != NULL) {
01501               static unsigned char nitems;
01502           
01503               /* Do whatever needs to be done when a menu is open. */
01504 
01505               /* First check if the mouse pointer is in the currently open
01506                  menu. */
01507               if(menus.open == &desktopmenu) {
01508                 menux = width - CTK_CONF_MENUWIDTH;
01509               } else {
01510                 menux = 1;
01511                 for(menu = menus.menus->next; menu != menus.open;
01512                     menu = menu->next) {
01513                   menux += menu->titlelen;
01514                 }
01515               }
01516 
01517               nitems = menus.open->nitems;
01518               /* Find out which of the menu items the mouse is pointing
01519                  to. */
01520               if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
01521                 if(myc <= nitems) {
01522                   menus.open->active = myc;
01523                 } else {
01524                   menus.open->active = nitems - 1;
01525                 }
01526               }
01527           
01528               if(mouse_clicked) {
01529                 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
01530                    myc <= nitems) {
01531                   redraw |= activate_menu();
01532                 } else {
01533                   lastmenu = menus.open;
01534                   menus.open = NULL;
01535                   redraw |= REDRAW_MENUPART;
01536                 }
01537               } else {
01538                 redraw |= REDRAW_MENUS;
01539               }
01540             } else {
01541 
01542               /* Walk through the windows from top to bottom to see in
01543                  which window the mouse pointer is. */
01544               if(dialog != NULL) {
01545                 window = dialog;
01546               } else {
01547                 for(window = windows; window != NULL;
01548                     window = window->next) {
01549               
01550                   /* Check if the mouse is within the window. */
01551                   if(mxc >= window->x &&
01552                      mxc <= window->x + window->w +
01553                      2 * ctk_draw_windowborder_width &&
01554                      myc >= window->y &&
01555                      myc <= window->y + window->h +
01556                      ctk_draw_windowtitle_height +
01557                      ctk_draw_windowborder_height) {
01558                     break;
01559                   }
01560                 }
01561               }
01562 
01563 
01564               /* If we didn't find any window, and there are no windows
01565                  open, the mouse pointer will definately be within the
01566                  background desktop window. */
01567               if(window == NULL) {
01568                 window = &desktop_window;
01569               }
01570 
01571               /* If the mouse pointer moves around outside of the
01572                  currently focused window (or dialog), we should not have
01573                  any focused widgets in the focused window so we make sure
01574                  that there are none. */
01575               if(windows != NULL &&
01576                  window != windows &&
01577                  windows->focused != NULL){
01578                 /*add_redrawwidget(windows->focused);
01579                   windows->focused = NULL;
01580                   redraw |= REDRAW_WIDGETS;*/
01581                 unfocus_widget(windows->focused);
01582               }
01583 
01584               if(window != NULL) {
01585                 /* If the mouse was clicked outside of the current window,
01586                    we bring the clicked window to front. */
01587                 if(dialog == NULL &&
01588                    window != &desktop_window &&
01589                    window != windows &&
01590                    mouse_clicked) {
01591                   /* Bring window to front. */
01592                   ctk_window_open(window);
01593                   redraw |= REDRAW_ALL;
01594                 } else {
01595           
01596                   /* Find out which widget currently is under the mouse
01597                      pointer and give it focus, unless it already has
01598                      focus. */
01599                   mxc = mxc - window->x - ctk_draw_windowborder_width;
01600                   myc = myc - window->y - ctk_draw_windowtitle_height;
01601             
01602                   /* See if the mouse pointer is on a widget. If so, it
01603                      should be selected and, if the button is clicked,
01604                      activated. */
01605                   for(widget = window->active; widget != NULL;
01606                       widget = widget->next) {
01607                 
01608                     if(mxc >= widget->x &&
01609                        mxc <= widget->x + widget->w &&
01610                        (myc == widget->y ||
01611                         ((widget->type == CTK_WIDGET_BITMAP ||
01612                           /*widget->type == CTK_WIDGET_TEXTMAP ||*/
01613                           widget->type == CTK_WIDGET_ICON) &&
01614                          (myc >= widget->y &&
01615                           myc <= widget->y +
01616                           ((struct ctk_bitmap *)widget)->h)))) {
01617                       break;
01618                     }
01619                   }
01620             
01621 
01622                   /* if the mouse is moved in the focused window, we emit
01623                      a ctk_signal_pointer_move signal to the owner of the
01624                      window. */
01625                   if(mouse_moved &&
01626                      (window != &desktop_window ||
01627                       windows == NULL)) {
01628 
01629                     process_post(window->owner, ctk_signal_pointer_move, NULL);
01630 
01631                     /* If there was a focused widget that is not below the
01632                        mouse pointer, we remove focus from the widget and
01633                        redraw it. */
01634                     if(window->focused != NULL &&
01635                        widget != window->focused) {
01636                       /*                  add_redrawwidget(window->focused);
01637                                           if(CTK_WIDGET_TYPE(window->focused) ==
01638                                           CTK_WIDGET_TEXTENTRY) {
01639                                           ((struct ctk_textentry *)(window->focused))->state =
01640                                           CTK_TEXTENTRY_NORMAL;
01641                                           }
01642                                           window->focused = NULL;*/
01643                       unfocus_widget(window->focused);
01644                     }
01645                     redraw |= REDRAW_WIDGETS;
01646                     if(widget != NULL) {
01647                       select_widget(widget);
01648                     }
01649                   }
01650             
01651                   if(mouse_button_changed) {
01652                     process_post(window->owner, ctk_signal_pointer_button,
01653                                  (process_data_t)mouse_button);
01654                     if(mouse_clicked && widget != NULL) {
01655                       select_widget(widget);
01656                       redraw |= activate(widget);
01657                     }
01658                   }
01659                 }
01660               }
01661             }
01662           }
01663         }
01664 #endif /* CTK_CONF_MOUSE_SUPPORT */
01665     
01666         while(ctk_arch_keyavail()) {
01667 
01668           ctk_mouse_hide();
01669       
01670           screensaver_timer = 0;
01671       
01672           c = ctk_arch_getkey();
01673       
01674           if(dialog != NULL) {
01675             window = dialog;
01676           } else if(windows != NULL) {
01677             window = windows;
01678           } else {
01679             window = &desktop_window;
01680           }
01681       
01682           widget = window->focused;
01683           
01684           if(widget != NULL &&
01685              widget->type == CTK_WIDGET_TEXTENTRY &&
01686              widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
01687             textentry_input(c, (struct ctk_textentry *)widget);
01688             add_redrawwidget(widget);
01689 #if CTK_CONF_MENUS
01690           } else if(menus.open != NULL) {
01691             redraw |= menus_input(c);
01692 #endif /* CTK_CONF_MENUS */
01693           } else {
01694             switch(c) {
01695             case CTK_CONF_WIDGETDOWN_KEY:
01696               switch_focus_widget(DOWN);
01697               break;
01698             case CTK_CONF_WIDGETUP_KEY:
01699               switch_focus_widget(UP);
01700               break;
01701 #if CTK_CONF_MENUS
01702             case CTK_CONF_MENU_KEY:
01703               if(dialog == NULL) {
01704                 if(lastmenu == NULL) {
01705                   menus.open = menus.menus;
01706                 } else {
01707                   menus.open = lastmenu;
01708                 }
01709                 menus.open->active = 0;
01710                 redraw |= REDRAW_MENUS;
01711               }
01712               break;
01713 #endif /* CTK_CONF_MENUS */
01714             case CTK_CONF_WINDOWSWITCH_KEY:
01715               if(windows != NULL) {
01716                 for(window = windows; window->next != NULL;
01717                     window = window->next);
01718                 ctk_window_open(window);
01719               }
01720               break;
01721             default:
01722 
01723               if(c == CH_ENTER &&
01724                  widget != NULL) {
01725                 redraw |= activate(widget);
01726               } else {
01727                 if(widget != NULL &&
01728                    widget->type == CTK_WIDGET_TEXTENTRY) {
01729                   if(widget->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
01730                     widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
01731                     textentry_input(0, (struct ctk_textentry *)widget);
01732                   }
01733                   textentry_input(c, (struct ctk_textentry *)widget);
01734                   add_redrawwidget(widget);
01735                 } else {
01736                   /*          window->focused = NULL;*/
01737                   unfocus_widget(window->focused);
01738                   process_post_synch(window->owner, ctk_signal_keypress,
01739                                      (process_data_t)c);
01740                 }
01741               }
01742               break;
01743             }
01744           }
01745 
01746 #if 0
01747           if(redraw & REDRAW_WIDGETS) {
01748             widgetptr = redraw_widgets;
01749             for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
01750               widget_redraw(*widgetptr);
01751               *widgetptr = NULL;
01752               ++widgetptr;
01753             }
01754             redraw &= ~REDRAW_WIDGETS;
01755             redraw_widgetptr = 0;
01756           }
01757 #endif /* 0 */
01758         }
01759 #if CTK_CONF_WINDOWMOVE
01760       } else if(mode == CTK_MODE_WINDOWMOVE) {
01761 
01762         redraw = 0;
01763 
01764         window = windows;
01765 
01766 #if CTK_CONF_MOUSE_SUPPORT
01767 
01768         /* If the mouse has moved, we move the window as well. */
01769         if(mouse_moved) {
01770 
01771           if(window->w + mxc + 2 >= width) {
01772             window->x = width - 2 - window->w;
01773           } else {
01774             window->x = mxc;
01775           }
01776 
01777           if(window->h + myc + ctk_draw_windowtitle_height +
01778              ctk_draw_windowborder_height >= height) {
01779             window->y = height - window->h -
01780               ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
01781           } else {
01782             window->y = myc;
01783           }
01784           if(window->y > 0) {
01785             --window->y;
01786           }
01787 
01788           redraw = REDRAW_ALL;
01789         }
01790     
01791         /* Check if the mouse has been clicked, and stop moving the window
01792            if so. */
01793         if(mouse_button_changed &&
01794            mouse_button == 0) {
01795           mode = CTK_MODE_NORMAL;
01796           redraw = REDRAW_ALL;
01797         }
01798 #endif /* CTK_CONF_MOUSE_SUPPORT */
01799     
01800         while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
01801     
01802           screensaver_timer = 0;
01803       
01804           c = ctk_arch_getkey();
01805       
01806           switch(c) {
01807           case CH_CURS_RIGHT:
01808             ++window->x;
01809             if(window->x + window->w + 1 >= width) {
01810               --window->x;
01811             }
01812             redraw = REDRAW_ALL;
01813             break;
01814           case CH_CURS_LEFT:
01815             if(window->x > 0) {
01816               --window->x;
01817             }
01818             redraw = REDRAW_ALL;
01819             break;
01820           case CH_CURS_DOWN:
01821             ++window->y;
01822             if(window->y + window->h + 2 >= height) {
01823               --window->y;
01824             }
01825             redraw = REDRAW_ALL;
01826             break;
01827           case CH_CURS_UP:
01828             if(window->y > 0) {
01829               --window->y;
01830             }
01831             redraw = REDRAW_ALL;
01832             break;
01833           default:
01834             mode = CTK_MODE_NORMAL;
01835             redraw = REDRAW_ALL;
01836             break;
01837           }
01838         }
01839 #endif /* CTK_CONF_WINDOWMOVE */
01840       }
01841 
01842     if(redraw & REDRAW_ALL) {
01843       do_redraw_all(1, height);
01844 #if CTK_CONF_MENUS
01845     } else if(redraw & REDRAW_MENUPART) {
01846       do_redraw_all(1, maxnitems + 1);
01847     } else if(redraw & REDRAW_MENUS) {
01848       ctk_draw_menus(&menus);
01849 #endif /* CTK_CONF_MENUS */
01850     } else if(redraw & REDRAW_FOCUS) {
01851       if(dialog != NULL) {
01852         ctk_window_redraw(dialog);
01853       } else if(windows != NULL) {
01854         ctk_window_redraw(windows);
01855       } else {
01856         ctk_window_redraw(&desktop_window);
01857       }
01858     } else if(redraw & REDRAW_WIDGETS) {
01859       widgetptr = redraw_widgets;
01860       for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
01861         widget_redraw(*widgetptr);
01862         *widgetptr = NULL;
01863         ++widgetptr;
01864       }
01865     }
01866     redraw = 0;
01867     redraw_widgetptr = 0;
01868   }
01869   
01870   PROCESS_END();
01871 }
01872 /*---------------------------------------------------------------------------*/
01873 /** @} */
01874 /** @} */

Generated on Thu Jun 22 17:45:42 2006 for Contiki 2.x by  doxygen 1.4.4