Contiki 3.x
ctk.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2002-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 operating system.
31  *
32  *
33  */
34 
35 /**
36  * \file
37  * The Contiki Toolkit CTK, the Contiki GUI.
38  * \author Adam Dunkels <adam@dunkels.com>
39  */
40 
41 /**
42  * \defgroup ctk CTK graphical user interface
43  *
44  * The Contiki Toolkit (CTK) provides the graphical user interface for
45  * the Contiki system.
46  *
47  * @{
48  */
49 
50 #include <string.h>
51 
52 #include "contiki.h"
53 
54 #include "ctk/ctk.h"
55 #include "ctk/ctk-draw.h"
56 #include "ctk/ctk-mouse.h"
57 
58 static unsigned char height, width;
59 
60 static unsigned char mode;
61 
62 #if CTK_CONF_WINDOWS
63 static struct ctk_window desktop_window;
64 static struct ctk_window *windows;
65 static struct ctk_window *dialog;
66 #else /* CTK_CONF_WINDOWS */
67 static struct ctk_window *window;
68 #endif /* CTK_CONF_WINDOWS */
69 
70 #if CTK_CONF_MENUS
71 static struct ctk_menus menus;
72 static struct ctk_menu *lastmenu;
73 static struct ctk_menu desktopmenu;
74 static unsigned char maxnitems;
75 #endif /* CTK_CONF_MENUS */
76 
77 #ifndef NULL
78 #define NULL (void *)0
79 #endif /* NULL */
80 
81 #define REDRAW_NONE 0
82 #define REDRAW_ALL 1
83 #define REDRAW_FOCUS 2
84 #define REDRAW_WIDGETS 4
85 #define REDRAW_MENUS 8
86 #define REDRAW_MENUPART 16
87 
88 #define MAX_REDRAWWIDGETS 4
89 static unsigned char redraw;
90 static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
91 static unsigned char redraw_widgetptr;
92 
93 #if CTK_CONF_ICONS
94 static unsigned char iconx, icony;
95 #define ICONX_START (width - 6)
96 #define ICONY_START (height - 6 - CTK_CONF_MENUS)
97 #define ICONX_DELTA -16
98 #define ICONY_DELTA -5
99 #define ICONY_MAX height
100 #endif /* CTK_CONF_ICONS */
101 
102 #ifndef ctk_arch_keyavail
103 unsigned char ctk_arch_keyavail(void);
104 #endif /* ctk_arch_keyavail */
105 
106 #ifndef ctk_arch_getkey
108 #endif /* ctk_arch_getkey */
109 
110 #ifndef ctk_arch_isprint
111 unsigned char ctk_arch_isprint(ctk_arch_key_t key);
112 #endif /* ctk_arch_isprint */
113 
114 PROCESS(ctk_process, "CTK Contiki GUI");
115 
116 /**
117  * \defgroup ctkevents CTK events
118  * @{
119  */
120 process_event_t
121 
122  /**
123  * Emitted for every key being pressed.
124  *
125  * The key is passed as signal data.*/
127 
128  /** Emitted when a widget is activated (pressed). A pointer to the
129  widget is passed as signal data. */
131 
132  /** Same as ctk_signal_widget_activate. */
134 
135  /** Emitted when a widget is selected. A pointer to the widget is
136  passed as signal data. */
138 
139  /** Same as ctk_signal_widget_select. */
141 
142  /** Emitted when a hyperlink is activated. The signal is broadcast
143  to all listeners. */
145 
146  /** Same as ctk_signal_widget_select. */
148 
149  /** Emitted when a menu item is activated. The number of the menu
150  item is passed as signal data. */
151 process_event_t ctk_signal_menu_activate;
152 
153  /** Emitted when a window is closed. A pointer to the window is
154  passed as signal data. */
155 process_event_t ctk_signal_window_close;
156 
157 #if CTK_CONF_MOUSE_SUPPORT
158  /** Emitted when the mouse pointer is moved. A NULL pointer is
159  passed as signal data and it is up to the listening process to
160  check the position of the mouse using the CTK mouse API.*/
161 process_event_t ctk_signal_pointer_move,
162  /** Emitted when a mouse button is pressed. The button is passed as
163  signal data to the listening process. */
164  ctk_signal_pointer_button;
165 #endif /* CTK_CONF_MOUSE_SUPPORT */
166 
167 #if CTK_CONF_SCREENSAVER
168 /** Emitted when the user has been idle long enough for the
169  screensaver to start. */
170 process_event_t ctk_signal_screensaver_stop,
171  /** Emitted when the user presses a key or moves the mouse when the
172  screensaver is active. */
173  ctk_signal_screensaver_start;
174 #endif /* CTK_CONF_SCREENSAVER */
175 
176 /** @} */
177 
178 #if CTK_CONF_MOUSE_SUPPORT
179 unsigned short mouse_x, mouse_y, mouse_button;
180 #endif /* CTK_CONF_MOUSE_SUPPORT */
181 
182 #if CTK_CONF_SCREENSAVER
183 static unsigned short screensaver_timer = 0;
184 unsigned short ctk_screensaver_timeout = (5*60);
185 static struct timer timer;
186 #endif /* CTK_CONF_SCREENSAVER */
187 
188 static void CC_FASTCALL
189 textentry_input(ctk_arch_key_t c,
190  CC_REGISTER_ARG struct ctk_textentry *t);
191 
192 #if CTK_CONF_MENUS
193 /*---------------------------------------------------------------------------*/
194 /**
195  * \internal Creates the Desktop menu.
196  *
197  * Creates the leftmost menu, "Desktop". Since the desktop menu
198  * contains the list of all open windows, this function will be called
199  * whenever a window is opened or closed.
200  */
201 /*---------------------------------------------------------------------------*/
202 static void
203 make_desktopmenu(void)
204 {
205  struct ctk_window *w;
206 
207  desktopmenu.nitems = 0;
208 
209  if(windows == NULL) {
210  ctk_menuitem_add(&desktopmenu, "(No windows)");
211  } else {
212  for(w = windows; w != NULL; w = w->next) {
213  ctk_menuitem_add(&desktopmenu, w->title);
214  }
215  }
216 }
217 #endif /* CTK_CONF_MENUS */
218 /*---------------------------------------------------------------------------*/
219 #if CTK_CONF_ICONS
220 static void
221 arrange_icons(void)
222 {
223  struct ctk_widget *icon;
224 
225  iconx = ICONX_START;
226  icony = ICONY_START;
227 
228  for(icon = desktop_window.active; icon != NULL; icon = icon->next) {
229 
230  icon->x = iconx;
231  icon->y = icony;
232 
233  icony += ICONY_DELTA;
234  if(icony >= ICONY_MAX) {
235  icony = ICONY_START;
236  iconx += ICONX_DELTA;
237  }
238  }
239 }
240 #endif /* CTK_CONF_ICONS */
241 /*---------------------------------------------------------------------------*/
242 void
243 ctk_restore(void)
244 {
245  ctk_draw_init();
246 
247  height = ctk_draw_height();
248  width = ctk_draw_width();
249 
250 #if CTK_CONF_ICONS
251  arrange_icons();
252 #endif /* CTK_CONF_ICONS */
253 
254  redraw = REDRAW_ALL;
255 }
256 /*---------------------------------------------------------------------------*/
257 
258 /**
259  * \addtogroup ctkappfunc
260  * @{
261  */
262 
263 /*---------------------------------------------------------------------------*/
264 /**
265  * Sets the current CTK mode.
266  *
267  * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
268  * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
269  * keypresses and mouse pointer movements are processed and the screen
270  * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
271  * performed and the first key press or pointer movement will cause
272  * the ctk_signal_screensaver_stop to be emitted. In the
273  * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
274  * ignored and no screen redraws are made.
275  *
276  * \param m The mode.
277  */
278 /*---------------------------------------------------------------------------*/
279 void
280 ctk_mode_set(unsigned char m) {
281  mode = m;
282 }
283 /*---------------------------------------------------------------------------*/
284 /**
285  * Retrieves the current CTK mode.
286  *
287  * \return The current CTK mode.
288  */
289 /*---------------------------------------------------------------------------*/
290 unsigned char
292  return mode;
293 }
294 /*---------------------------------------------------------------------------*/
295 /**
296  * Add an icon to the desktop.
297  *
298  * \param icon The icon to be added.
299  *
300  * \param p The process that owns the icon.
301  */
302 /*---------------------------------------------------------------------------*/
303 void
304 ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, struct process *p)
305 {
306 #if CTK_CONF_ICONS
307  icon->widget.icon.owner = p;
308  ctk_widget_add(&desktop_window, icon);
309  arrange_icons();
310 #endif /* CTK_CONF_ICONS */
311 }
312 #if CTK_CONF_WINDOWS
313 /*---------------------------------------------------------------------------*/
314 /**
315  * Open a dialog box.
316  *
317  * \param d The dialog to be opened.
318  */
319 /*---------------------------------------------------------------------------*/
320 void
321 ctk_dialog_open(struct ctk_window *d)
322 {
323  dialog = d;
324  redraw |= REDRAW_FOCUS;
325 }
326 /*---------------------------------------------------------------------------*/
327 /**
328  * Close the dialog box, if one is open.
329  *
330  */
331 /*---------------------------------------------------------------------------*/
332 void
333 ctk_dialog_close(void)
334 {
335  dialog = NULL;
336  redraw |= REDRAW_ALL;
337 }
338 #endif /* CTK_CONF_WINDOWS */
339 /*---------------------------------------------------------------------------*/
340 /**
341  * Open a window, or bring window to front if already open.
342  *
343  * \param w The window to be opened.
344  */
345 /*---------------------------------------------------------------------------*/
346 void
348 {
349 #if CTK_CONF_WINDOWS
350  struct ctk_window *w2;
351 
352  /* Check if already open. */
353  for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
354  if(w2 == NULL) {
355  /* Not open, so we add it at the head of the list of open
356  windows. */
357  w->next = windows;
358  if(windows != NULL) {
359  windows->prev = w;
360  }
361  windows = w;
362  w->prev = NULL;
363  } else {
364  /* Window already open, so we move it to the front of the windows
365  list. */
366  if(w != windows) {
367  if(w->next != NULL) {
368  w->next->prev = w->prev;
369  }
370  if(w->prev != NULL) {
371  w->prev->next = w->next;
372  }
373  w->next = windows;
374  windows->prev = w;
375  windows = w;
376  w->prev = NULL;
377  }
378  }
379 #else /* CTK_CONF_WINDOWS */
380  window = w;
381 #endif /* CTK_CONF_WINDOWS */
382 
383 #if CTK_CONF_MENUS
384  /* Recreate the Desktop menu's window entries.*/
385  make_desktopmenu();
386 #endif /* CTK_CONF_MENUS */
387 
388  redraw |= REDRAW_ALL;
389 }
390 /*---------------------------------------------------------------------------*/
391 /**
392  * Close a window if it is open.
393  *
394  * If the window is not open, this function does nothing.
395  *
396  * \param w The window to be closed.
397  */
398 /*---------------------------------------------------------------------------*/
399 void
401 {
402 #if CTK_CONF_WINDOWCLOSE
403  static struct ctk_window *w2;
404 
405  if(w == NULL) {
406  return;
407  }
408 
409  /* Check if the window to be closed is the first window on the list. */
410  if(w == windows) {
411  windows = w->next;
412  if(windows != NULL) {
413  windows->prev = NULL;
414  }
415  w->next = w->prev = NULL;
416  } else {
417  /* Otherwise we step through the list until we find the window
418  before the one to be closed. We then redirect its ->next
419  pointer and its ->next->prev. */
420  for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
421 
422  if(w2 == NULL) {
423  /* The window wasn't open, so there is nothing more for us to do. */
424  return;
425  }
426 
427  if(w->next != NULL) {
428  w->next->prev = w->prev;
429  }
430  w2->next = w->next;
431 
432  w->next = w->prev = NULL;
433  }
434 
435 #if CTK_CONF_MENUS
436  /* Recreate the Desktop menu's window entries.*/
437  make_desktopmenu();
438 #endif /* CTK_CONF_MENUS */
439  redraw |= REDRAW_ALL;
440 #endif /* CTK_CONF_WINDOWCLOSE */
441 }
442 #if CTK_CONF_WINDOWS
443 /*---------------------------------------------------------------------------*/
444 /**
445  * \internal Create the move and close buttons on the window titlebar.
446  */
447 /*---------------------------------------------------------------------------*/
448 static void
449 make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
450 {
451  unsigned char placement;
452 
453  if(ctk_draw_windowtitle_height >= 2) {
454  placement = -1 - ctk_draw_windowtitle_height/2;
455  } else {
456  placement = -1;
457  }
458 #if CTK_CONF_WINDOWMOVE
459  CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
460  window->titlelen, window->title);
461 #else
462  CTK_LABEL_NEW(&window->titlebutton, 0, placement,
463  window->titlelen, 1, window->title);
464 #endif /* CTK_CONF_WINDOWMOVE */
465  CTK_WIDGET_ADD(window, &window->titlebutton);
466 
467 #if CTK_CONF_WINDOWCLOSE
468  CTK_BUTTON_NEW(&window->closebutton, window->w - 3, placement,
469  1, "x");
470 #else
471  CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
472  3, 1, " ");
473 #endif /* CTK_CONF_WINDOWCLOSE */
474  CTK_WIDGET_ADD(window, &window->closebutton);
475 }
476 #endif /* CTK_CONF_WINDOWS */
477 /*---------------------------------------------------------------------------*/
478 /**
479  * Remove all widgets from a window.
480  *
481  * \param w The window to be cleared.
482  */
483 /*---------------------------------------------------------------------------*/
484 void
486 {
487  w->active = w->inactive = w->focused = NULL;
488 
489 #if CTK_CONF_WINDOWS
490  make_windowbuttons(w);
491 #endif /* CTK_CONF_WINDOWS */
492 }
493 /*---------------------------------------------------------------------------*/
494 /**
495  * Add a menu to the menu bar.
496  *
497  * \param menu The menu to be added.
498  *
499  * \note Do not call this function multiple times for the same menu,
500  * as no check is made to see if the menu already is in the menu bar.
501  */
502 /*---------------------------------------------------------------------------*/
503 void
504 ctk_menu_add(struct ctk_menu *menu)
505 {
506 #if CTK_CONF_MENUS
507  struct ctk_menu *m;
508 
509  if(lastmenu == NULL) {
510  lastmenu = menu;
511  }
512 
513  for(m = menus.menus; m->next != NULL; m = m->next) {
514  if(m == menu) {
515  return;
516  }
517  }
518  m->next = menu;
519  menu->next = NULL;
520 
521  redraw |= REDRAW_MENUPART;
522 #endif /* CTK_CONF_MENUS */
523 }
524 /*---------------------------------------------------------------------------*/
525 /**
526  * Remove a menu from the menu bar.
527  *
528  * \param menu The menu to be removed.
529  */
530 /*---------------------------------------------------------------------------*/
531 void
533 {
534 #if CTK_CONF_MENUS
535  struct ctk_menu *m;
536 
537  for(m = menus.menus; m->next != NULL; m = m->next) {
538  if(m->next == menu) {
539  m->next = menu->next;
540  if(menu == lastmenu) {
541  lastmenu = NULL;
542  }
543  redraw |= REDRAW_MENUPART;
544  return;
545  }
546  }
547 #endif /* CTK_CONF_MENUS */
548 }
549 /*---------------------------------------------------------------------------*/
550 /**
551  * \internal Redraws everything on the screen within the clip
552  * interval.
553  *
554  * \param clipy1 The upper bound of the clip interval
555  * \param clipy2 The lower bound of the clip interval
556  */
557 /*---------------------------------------------------------------------------*/
558 static void CC_FASTCALL
559 do_redraw_all(unsigned char clipy1, unsigned char clipy2)
560 {
561 #if CTK_CONF_WINDOWS
562  static struct ctk_widget *widget;
563  struct ctk_window *w;
564  unsigned char focus;
565 #endif /* CTK_CONF_WINDOWS */
566 
567  if(mode != CTK_MODE_NORMAL && mode != CTK_MODE_WINDOWMOVE) {
568  return;
569  }
570 
571  ctk_draw_clear(clipy1, clipy2);
572 
573 #if CTK_CONF_WINDOWS
574  /* Draw widgets in root window */
575  for(widget = desktop_window.active;
576  widget != NULL; widget = widget->next) {
577  ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
578  }
579 
580  /* Draw windows */
581  if(windows != NULL) {
582  /* Find the last window.*/
583  for(w = windows; w->next != NULL; w = w->next);
584 
585  /* Draw the windows from back to front. */
586  for(; w != windows; w = w->prev) {
587  ctk_draw_clear_window(w, 0, clipy1, clipy2);
588  ctk_draw_window(w, 0, clipy1, clipy2, 1);
589  }
590 
591  /* Draw focused window */
592  focus = mode == CTK_MODE_WINDOWMOVE?
595  ctk_draw_clear_window(windows, focus, clipy1, clipy2);
596  ctk_draw_window(windows, focus, clipy1, clipy2, 1);
597  }
598 
599  /* Draw dialog (if any) */
600  if(dialog != NULL) {
601  ctk_draw_dialog(dialog);
602  }
603 #else /* CTK_CONF_WINDOWS */
604  if(window != NULL) {
605  ctk_draw_clear_window(window, CTK_FOCUS_WINDOW, clipy1, clipy2);
606  ctk_draw_window(window, CTK_FOCUS_WINDOW, clipy1, clipy2, 0);
607  }
608 #endif /* CTK_CONF_WINDOWS */
609 
610 #if CTK_CONF_MENUS
611  ctk_draw_menus(&menus);
612 #endif /* CTK_CONF_MENUS */
613 }
614 #if CTK_CONF_WINDOWS
615 /*---------------------------------------------------------------------------*/
616 /**
617  * Redraw the entire desktop.
618  *
619  * \param d The desktop to be redrawn.
620  *
621  * \note Currently the parameter d is not used, but must be set to
622  * NULL.
623  *
624  */
625 /*---------------------------------------------------------------------------*/
626 void
627 ctk_desktop_redraw(struct ctk_desktop *d)
628 {
629  if(PROCESS_CURRENT() == &ctk_process) {
630  if(mode == CTK_MODE_NORMAL || mode == CTK_MODE_WINDOWMOVE) {
631  do_redraw_all(CTK_CONF_MENUS, height);
632  }
633  } else {
634  height = ctk_draw_height();
635  width = ctk_draw_width();
636 
637  redraw |= REDRAW_ALL;
638  }
639 }
640 #endif /* CTK_CONF_WINDOWS */
641 /*---------------------------------------------------------------------------*/
642 /**
643  * Redraw a window.
644  *
645  * This function redraws the window, but only if it is the foremost
646  * one on the desktop.
647  *
648  * \param w The window to be redrawn.
649  */
650 /*---------------------------------------------------------------------------*/
651 void
653 {
654  /* Only redraw the window if it is a dialog or if it is the foremost
655  window. */
656  if(mode != CTK_MODE_NORMAL) {
657  return;
658  }
659 
660 #if CTK_CONF_WINDOWS
661  if(w == dialog) {
662  ctk_draw_dialog(w);
663  } else if(dialog == NULL &&
664 #if CTK_CONF_MENUS
665  menus.open == NULL &&
666 #endif /* CTK_CONF_MENUS */
667  windows == w)
668 #endif /* CTK_CONF_WINDOWS */
669  {
670  ctk_draw_window(w, CTK_FOCUS_WINDOW, 0, height, 0);
671  }
672 }
673 /*---------------------------------------------------------------------------*/
674 /**
675  * \internal Creates a new window.
676  *
677  * \param window The window to be created.
678  * \param w The width of the window.
679  * \param h The height of the window.
680  * \param title The title of the window.
681  */
682 /*---------------------------------------------------------------------------*/
683 static void
684 window_new(CC_REGISTER_ARG struct ctk_window *window,
685  unsigned char w, unsigned char h, char *title)
686 {
687 #if CTK_CONF_WINDOWS
688  if(w >= width - 2) {
689  window->x = 0;
690  } else {
691  window->x = (width - w - 2) / 2;
692  }
693  if(h >= height - 2 - ctk_draw_windowtitle_height) {
694  window->y = 0;
695  } else {
696  window->y = (height - h - 2 - ctk_draw_windowtitle_height) / 2;
697  }
698 #endif /* CTK_CONF_WINDOWS */
699 
700  window->w = w;
701  window->h = h;
702  window->title = title;
703  if(title != NULL) {
704  window->titlelen = (unsigned char)strlen(title);
705  } else {
706  window->titlelen = 0;
707  }
708  window->next = window->prev = NULL;
709  window->owner = PROCESS_CURRENT();
710  window->active = window->inactive = window->focused = NULL;
711 }
712 /*---------------------------------------------------------------------------*/
713 /**
714  * Create a new window.
715  *
716  * Creates a new window. The memory for the window structure must
717  * already be allocated by the caller, and is usually done with a
718  * static declaration.
719  *
720  * This function sets up the internal structure of the ctk_window
721  * struct and creates the move and close buttons, but it does not open
722  * the window. The window must be explicitly opened by calling the
723  * ctk_window_open() function.
724  *
725  * \param window The window to be created.
726  * \param w The width of the new window.
727  * \param h The height of the new window.
728  * \param title The title of the new window.
729  */
730 /*---------------------------------------------------------------------------*/
731 void
732 ctk_window_new(struct ctk_window *window,
733  unsigned char w, unsigned char h, char *title)
734 {
735  window_new(window, w, h, title);
736 
737 #if CTK_CONF_WINDOWS
738  make_windowbuttons(window);
739 #endif /* CTK_CONF_WINDOWS */
740 }
741 #if CTK_CONF_WINDOWS
742 /*---------------------------------------------------------------------------*/
743 /**
744  * Creates a new dialog.
745  *
746  * This function only sets up the internal structure of the ctk_window
747  * struct but does not open the dialog. The dialog must be explicitly
748  * opened by calling the ctk_dialog_open() function.
749  *
750  * \param dialog The dialog to be created.
751  * \param w The width of the dialog.
752  * \param h The height of the dialog.
753  */
754 /*---------------------------------------------------------------------------*/
755 void
756 ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
757  unsigned char w, unsigned char h)
758 {
759  window_new(dialog, w, h, NULL);
760 }
761 #endif /* CTK_CONF_WINDOWS */
762 /*---------------------------------------------------------------------------*/
763 /**
764  * Creates a new menu.
765  *
766  * This function sets up the internal structure of the menu, but does
767  * not add it to the menubar. Use the function ctk_menu_add() for that
768  * purpose.
769  *
770  * \param menu The menu to be created.
771  * \param title The title of the menu.
772  */
773 /*---------------------------------------------------------------------------*/
774 void
775 ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu, char *title)
776 {
777 #if CTK_CONF_MENUS
778  menu->next = NULL;
779  menu->title = title;
780  menu->titlelen = (unsigned char)strlen(title);
781  menu->active = 0;
782  menu->nitems = 0;
783 #endif /* CTK_CONF_MENUS */
784 }
785 /*---------------------------------------------------------------------------*/
786 /**
787  * Adds a menu item to a menu.
788  *
789  * In CTK, each menu item is identified by a number which is unique
790  * within each menu. When a menu item is selected, a
791  * ctk_menuitem_activated signal is emitted and the menu item number
792  * is passed as signal data with the signal.
793  *
794  * \param menu The menu to which the menu item should be added.
795  * \param name The name of the menu item.
796  * \return The number of the menu item.
797  */
798 /*---------------------------------------------------------------------------*/
799 unsigned char
800 ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu, char *name)
801 {
802 #if CTK_CONF_MENUS
803  if(menu->nitems == CTK_MAXMENUITEMS) {
804  return 0;
805  }
806  menu->items[menu->nitems].title = name;
807  menu->items[menu->nitems].titlelen = (unsigned char)strlen(name);
808  return menu->nitems++;
809 #else
810  return 0;
811 #endif /* CTK_CONF_MENUS */
812 }
813 /*---------------------------------------------------------------------------*/
814 /**
815  * \internal Adds a widget to the list of widgets that should be
816  * redrawn.
817  *
818  * \param w The widget that should be redrawn.
819  */
820 /*---------------------------------------------------------------------------*/
821 static void CC_FASTCALL
822 add_redrawwidget(struct ctk_widget *w)
823 {
824  static unsigned char i;
825 
826  if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
827  redraw |= REDRAW_FOCUS;
828  } else {
829  redraw |= REDRAW_WIDGETS;
830  /* Check if it is in the queue already. If so, we don't add it
831  again. */
832  for(i = 0; i < redraw_widgetptr; ++i) {
833  if(redraw_widgets[i] == w) {
834  return;
835  }
836  }
837  redraw_widgets[redraw_widgetptr++] = w;
838  }
839 }
840 /*---------------------------------------------------------------------------*/
841 /**
842  * \internal Checks if a widget redrawn and adds it to the list of
843  * widgets to be redrawn.
844  *
845  * A widget can be redrawn only if the current CTK mode is
846  * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
847  * foremost window.
848  *
849  * \param widget The widget that should be redrawn.
850  */
851 /*---------------------------------------------------------------------------*/
852 static void
853 widget_redraw(struct ctk_widget *widget)
854 {
855  struct ctk_window *window;
856 
857  if(mode != CTK_MODE_NORMAL || widget == NULL) {
858  return;
859  }
860 
861  /* Only redraw widgets that are in the foremost window. If we would
862  allow redrawing widgets in non-focused windows, we would have to
863  redraw all the windows that cover the non-focused window as well,
864  which would lead to flickering.
865 
866  Also, we avoid drawing any widgets when the menus are active.
867  */
868 
869 #if CTK_CONF_MENUS
870  if(menus.open == NULL)
871 #endif /* CTK_CONF_MENUS */
872  {
873  window = widget->window;
874 #if CTK_CONF_WINDOWS
875  if(window == dialog) {
876  ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
877  } else if(dialog == NULL &&
878  (window == windows ||
879  window == &desktop_window))
880 #endif /* CTK_CONF_WINDOWS */
881  {
882  ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
883  }
884  }
885 }
886 /*---------------------------------------------------------------------------*/
887 /**
888  * Redraws a widget.
889  *
890  * This function will set a flag which causes the widget to be redrawn
891  * next time the CTK process is scheduled.
892  *
893  * \param widget The widget that is to be redrawn.
894  *
895  * \note This function should usually not be called directly since it
896  * requires typecasting of the widget parameter. The wrapper macro
897  * CTK_WIDGET_REDRAW() does the required typecast and should be used
898  * instead.
899  */
900 /*---------------------------------------------------------------------------*/
901 void
903 {
904  if(mode != CTK_MODE_NORMAL || widget == NULL) {
905  return;
906  }
907 
908  /* Since this function isn't called by CTK itself, we only queue the
909  redraw request. */
910  add_redrawwidget(widget);
911 }
912 /*---------------------------------------------------------------------------*/
913 /**
914  * Adds a widget to a window.
915  *
916  * This function adds a widget to a window. The order of which the
917  * widgets are added is important, as it sets the order to which
918  * widgets are cycled with the widget selection keys.
919  *
920  * \param window The window to which the widhet should be added.
921  * \param widget The widget to be added.
922  */
923 /*---------------------------------------------------------------------------*/
924 void CC_FASTCALL
926  CC_REGISTER_ARG struct ctk_widget *widget)
927 {
928  if(widget->type == CTK_WIDGET_LABEL ||
929  widget->type == CTK_WIDGET_SEPARATOR) {
930  widget->next = window->inactive;
931  window->inactive = widget;
932  widget->window = window;
933  } else {
934  widget->next = window->active;
935  window->active = widget;
936  widget->window = window;
937  }
938 }
939 /*---------------------------------------------------------------------------*/
940 /**
941  * Gets the width of the desktop.
942  *
943  * \param d The desktop.
944  * \return The width of the desktop, in characters.
945  *
946  * \note The d parameter is currently unused and must be set to NULL.
947  */
948 /*---------------------------------------------------------------------------*/
949 unsigned char
950 ctk_desktop_width(struct ctk_desktop *d)
951 {
952  return ctk_draw_width();
953 }
954 /*---------------------------------------------------------------------------*/
955 /**
956  * Gets the height of the desktop.
957  *
958  * \param d The desktop.
959  * \return The height of the desktop, in characters.
960  *
961  * \note The d parameter is currently unused and must be set to NULL.
962  */
963 /*---------------------------------------------------------------------------*/
964 unsigned char
965 ctk_desktop_height(struct ctk_desktop *d)
966 {
967  return ctk_draw_height();
968 }
969 /*---------------------------------------------------------------------------*/
970 /**
971  * \internal Selects a widget in the window of the widget.
972  *
973  * \param focus The widget to be focused.
974  */
975 /*---------------------------------------------------------------------------*/
976 static void CC_FASTCALL
977 select_widget(struct ctk_widget *focus)
978 {
979  struct ctk_window *window;
980 
981  window = focus->window;
982 
983  if(focus != window->focused) {
984  window->focused = focus;
985  /* The operation changed the focus, so we emit a "hover" signal
986  for those widgets that support it. */
987 
988  if(window->focused->type == CTK_WIDGET_HYPERLINK) {
990  } else if(window->focused->type == CTK_WIDGET_BUTTON) {
992  }
993 
994  add_redrawwidget(window->focused);
995 
997  }
998 }
999 /*---------------------------------------------------------------------------*/
1000 #define UP 0
1001 #define DOWN 1
1002 #define LEFT 2
1003 #define RIGHT 3
1004 static void CC_FASTCALL
1005 switch_focus_widget(unsigned char direction)
1006 {
1007 #if CTK_CONF_WINDOWS
1008  register struct ctk_window *window;
1009 #endif /* CTK_CONF_WINDOWS */
1010  register struct ctk_widget *focus;
1011  struct ctk_widget *widget;
1012 
1013 #if CTK_CONF_WINDOWS
1014  if(dialog != NULL) {
1015  window = dialog;
1016  } else {
1017  window = windows;
1018  }
1019 
1020  /* If there are no windows open, we move focus around between the
1021  icons on the root window instead. */
1022  if(window == NULL) {
1023  window = &desktop_window;
1024  }
1025 #else /* CTK_CONF_WINDOWS */
1026  if(window == NULL) {
1027  return;
1028  }
1029 #endif /* CTK_CONF_WINDOWS */
1030 
1031  focus = window->focused;
1032  if(focus == NULL) {
1033  focus = window->active;
1034  if(focus == NULL) {
1035  return;
1036  }
1037  }
1038  add_redrawwidget(focus);
1039 
1040  if((direction & 1) == 0) {
1041  /* Move focus "up" */
1042  focus = focus->next;
1043  } else {
1044  /* Move focus "down" */
1045  for(widget = window->active;
1046  widget != NULL; widget = widget->next) {
1047  if(widget->next == focus) {
1048  break;
1049  }
1050  }
1051  focus = widget;
1052  if(focus == NULL) {
1053  if(window->active != NULL) {
1054  for(focus = window->active;
1055  focus->next != NULL; focus = focus->next);
1056  }
1057  }
1058  }
1059  if(focus == NULL) {
1060  focus = window->active;
1061  }
1062 
1063  select_widget(focus);
1064 }
1065 /*---------------------------------------------------------------------------*/
1066 #if CTK_CONF_MENUS
1067 static void
1068 switch_open_menu(unsigned char rightleft)
1069 {
1070  struct ctk_menu *menu;
1071 
1072  if(rightleft == 0) {
1073  /* Move right */
1074  for(menu = menus.menus; menu != NULL; menu = menu->next) {
1075  if(menu->next == menus.open) {
1076  break;
1077  }
1078  }
1079  lastmenu = menus.open;
1080  menus.open = menu;
1081  if(menus.open == NULL) {
1082  for(menu = menus.menus;
1083  menu->next != NULL; menu = menu->next);
1084  menus.open = menu;
1085  }
1086  } else {
1087  /* Move to left */
1088  lastmenu = menus.open;
1089  menus.open = menus.open->next;
1090  if(menus.open == NULL) {
1091  menus.open = menus.menus;
1092  }
1093  }
1094 
1095  menus.open->active = 0;
1096 }
1097 /*---------------------------------------------------------------------------*/
1098 static void
1099 switch_menu_item(unsigned char updown)
1100 {
1101  register struct ctk_menu *m;
1102 
1103  m = menus.open;
1104 
1105  if(updown == 0) {
1106  /* Move up */
1107  if(m->active == 0) {
1108  m->active = m->nitems - 1;
1109  } else {
1110  --m->active;
1111  if(m->items[m->active].title[0] == '-') {
1112  --m->active;
1113  }
1114  }
1115  } else {
1116  /* Move down */
1117  if(m->active >= m->nitems - 1) {
1118  m->active = 0;
1119  } else {
1120  ++m->active;
1121  if(m->items[m->active].title[0] == '-') {
1122  ++m->active;
1123  }
1124  }
1125  }
1126 }
1127 #endif /* CTK_CONF_MENUS */
1128 /*---------------------------------------------------------------------------*/
1129 static unsigned char CC_FASTCALL
1130 activate(CC_REGISTER_ARG struct ctk_widget *w)
1131 {
1132  if(w->type == CTK_WIDGET_BUTTON) {
1133 #if CTK_CONF_WINDOWCLOSE
1134  if(w == (struct ctk_widget *)&windows->closebutton) {
1135  process_post(w->window->owner, ctk_signal_window_close, windows);
1136  ctk_window_close(windows);
1137  return REDRAW_ALL;
1138  } else
1139 #endif /* CTK_CONF_WINDOWCLOSE */
1140 #if CTK_CONF_WINDOWMOVE
1141  if(w == (struct ctk_widget *)&windows->titlebutton) {
1142  mode = CTK_MODE_WINDOWMOVE;
1143  return REDRAW_ALL;
1144  } else
1145 #endif /* CTK_CONF_WINDOWMOVE */
1146  {
1147  process_post(w->window->owner, ctk_signal_widget_activate, w);
1148  }
1149 #if CTK_CONF_ICONS
1150  } else if(w->type == CTK_WIDGET_ICON) {
1151  if(w->widget.icon.owner != PROCESS_NONE) {
1152  process_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1153  } else {
1154  process_post(w->window->owner, ctk_signal_widget_activate, w);
1155  }
1156 #endif /* CTK_CONF_ICONS */
1157  } else if(w->type == CTK_WIDGET_HYPERLINK) {
1158  process_post(PROCESS_BROADCAST, ctk_signal_hyperlink_activate, w);
1159  } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1160  if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1161  w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1162  textentry_input(0, (struct ctk_textentry *)w);
1163  } else {
1164  w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
1165  process_post(w->window->owner, ctk_signal_widget_activate, w);
1166  }
1167  add_redrawwidget(w);
1168  return REDRAW_WIDGETS;
1169  } else {
1170  process_post(w->window->owner, ctk_signal_widget_activate, w);
1171  }
1172  return REDRAW_NONE;
1173 }
1174 /*---------------------------------------------------------------------------*/
1175 #ifdef SDCC
1176 /* Dummy function that we define to keep sdcc happy - with sdcc,
1177  function pointers cannot be NULL. ctk_textentry_input is typedef'd
1178  in ctk/ctk.h, hence the strange-looking function signature. */
1179 unsigned char
1180 ctk_textentry_input_null(ctk_arch_key_t c, struct ctk_textentry *t)
1181 {
1182  return 0;
1183 }
1184 #endif /* SDCC */
1185 /*---------------------------------------------------------------------------*/
1186 static void CC_FASTCALL
1187 textentry_input(ctk_arch_key_t c, CC_REGISTER_ARG struct ctk_textentry *t)
1188 {
1189  register char *cptr, *cptr2;
1190  static unsigned char len, txpos, typos, tlen;
1191 
1192  if(t->input != NULL && t->input(c, t)) {
1193  return;
1194  }
1195 
1196  txpos = t->xpos;
1197  typos = t->ypos;
1198  tlen = t->len;
1199 
1200  cptr = &t->text[txpos + typos * (tlen + 1)];
1201 
1202  switch(c) {
1203  case CH_CURS_LEFT:
1204  if(txpos > 0) {
1205  --txpos;
1206  }
1207  break;
1208 
1209  case CH_CURS_RIGHT:
1210  if(txpos < tlen - 1 && *cptr != 0) {
1211  ++txpos;
1212  }
1213  break;
1214 
1215  case CH_CURS_UP:
1216  txpos = 0;
1217  break;
1218 
1219  case 0:
1220  case CH_CURS_DOWN:
1221  txpos = (unsigned char)strlen(t->text);
1222  if(txpos == tlen) {
1223  --txpos;
1224  }
1225  break;
1226 
1227  case CH_ENTER:
1228  activate((struct ctk_widget *)t);
1229  switch_focus_widget(DOWN);
1230  break;
1231 
1232  case CTK_CONF_WIDGETDOWN_KEY:
1233  t->state = CTK_TEXTENTRY_NORMAL;
1234  switch_focus_widget(DOWN);
1235  break;
1236  case CTK_CONF_WIDGETUP_KEY:
1237  t->state = CTK_TEXTENTRY_NORMAL;
1238  switch_focus_widget(UP);
1239  break;
1240 
1241  default:
1242  len = tlen - txpos;
1243  if(c == CH_DEL) {
1244  if(len == 1 && *cptr != 0) {
1245  *cptr = 0;
1246  } else {
1247  if(txpos > 0) {
1248  --txpos;
1249  strcpy(cptr - 1, cptr);
1250  }
1251  }
1252  } else {
1253  if(ctk_arch_isprint(c)) {
1254  if(len > 1) {
1255  cptr2 = cptr + len - 1;
1256  while(cptr2 > cptr) {
1257  *cptr2 = *(cptr2 - 1);
1258  --cptr2;
1259  }
1260  ++txpos;
1261  }
1262  *cptr = c;
1263  }
1264  }
1265  break;
1266  }
1267 
1268  t->xpos = txpos;
1269  t->ypos = typos;
1270 }
1271 /*---------------------------------------------------------------------------*/
1272 #if CTK_CONF_MENUS
1273 static unsigned char
1274 activate_menu(void)
1275 {
1276  struct ctk_window *w;
1277 
1278  lastmenu = menus.open;
1279  if(menus.open == &desktopmenu) {
1280  for(w = windows; w != NULL; w = w->next) {
1281  if(w->title == desktopmenu.items[desktopmenu.active].title) {
1282  ctk_window_open(w);
1283  menus.open = NULL;
1284  return REDRAW_ALL;
1285  }
1286  }
1287  } else {
1288  process_post(PROCESS_BROADCAST, ctk_signal_menu_activate, menus.open);
1289  }
1290  menus.open = NULL;
1291  return REDRAW_MENUPART;
1292 }
1293 /*---------------------------------------------------------------------------*/
1294 static unsigned char
1295 menus_input(ctk_arch_key_t c)
1296 {
1297  if(menus.open->nitems > maxnitems) {
1298  maxnitems = menus.open->nitems;
1299  }
1300 
1301  switch(c) {
1302  case CH_CURS_RIGHT:
1303  switch_open_menu(1);
1304  return REDRAW_MENUPART;
1305 
1306  case CH_CURS_DOWN:
1307  switch_menu_item(1);
1308  return REDRAW_MENUS;
1309 
1310  case CH_CURS_LEFT:
1311  switch_open_menu(0);
1312  return REDRAW_MENUPART;
1313 
1314  case CH_CURS_UP:
1315  switch_menu_item(0);
1316  return REDRAW_MENUS;
1317 
1318  case CH_ENTER:
1319  return activate_menu();
1320 
1321  case CTK_CONF_MENU_KEY:
1322  lastmenu = menus.open;
1323  menus.open = NULL;
1324  return REDRAW_MENUPART;
1325  }
1326 
1327  return REDRAW_NONE;
1328 }
1329 #endif /* CTK_CONF_MENUS */
1330 /*---------------------------------------------------------------------------*/
1331 #if CTK_CONF_SCREENSAVER
1332 static void
1333 handle_timer(void)
1334 {
1335  if(mode == CTK_MODE_NORMAL) {
1336  ++screensaver_timer;
1337  if(screensaver_timer >= ctk_screensaver_timeout) {
1338  process_post(PROCESS_BROADCAST, ctk_signal_screensaver_start, NULL);
1339 #ifdef CTK_SCREENSAVER_INIT
1340  CTK_SCREENSAVER_INIT();
1341 #endif /* CTK_SCREENSAVER_INIT */
1342 
1343  screensaver_timer = 0;
1344  }
1345  }
1346 }
1347 #endif /* CTK_CONF_SCREENSAVER */
1348 /*---------------------------------------------------------------------------*/
1349 static void
1350 unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1351 {
1352  if(w != NULL) {
1353  redraw |= REDRAW_WIDGETS;
1354  add_redrawwidget(w);
1356  ((struct ctk_textentry *)w)->state =
1357  CTK_TEXTENTRY_NORMAL;
1358  }
1359  w->window->focused = NULL;
1360  }
1361 }
1362 /*---------------------------------------------------------------------------*/
1363 PROCESS_THREAD(ctk_process, ev, data)
1364 {
1365  static ctk_arch_key_t c;
1366  static unsigned char i;
1367 #if CTK_CONF_WINDOWS
1368  register struct ctk_window *window;
1369 #endif /* CTK_CONF_WINDOWS */
1370  register struct ctk_widget *widget;
1371  register struct ctk_widget **widgetptr;
1372 #if CTK_CONF_MOUSE_SUPPORT
1373  static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1374  mouse_clicked;
1375 #if CTK_CONF_MENUS
1376  static unsigned char menux;
1377  register struct ctk_menu *menu;
1378 #endif /* CTK_CONF_MENUS */
1379 #endif /* CTK_CONF_MOUSE_SUPPORT */
1380 
1381  PROCESS_BEGIN();
1382 
1383 #if CTK_CONF_MENUS
1384  ctk_menu_new(&desktopmenu, "Desktop");
1385  make_desktopmenu();
1386  menus.menus = menus.desktopmenu = &desktopmenu;
1387 #endif /* CTK_CONF_MENUS */
1388 
1389 #if CTK_CONF_MOUSE_SUPPORT
1390  ctk_mouse_init();
1391  ctk_mouse_show();
1392 #endif /* CTK_CONF_MOUSE_SUPPORT */
1393 
1394  ctk_restore();
1395 
1396 #if CTK_CONF_WINDOWS
1397  desktop_window.owner = &ctk_process;
1398 #endif /* CTK_CONF_WINDOWS */
1399 
1401 
1404 
1408 
1410 
1412 
1414 
1415 #if CTK_CONF_MOUSE_SUPPORT
1416  ctk_signal_pointer_move = process_alloc_event();
1417  ctk_signal_pointer_button = process_alloc_event();
1418 #endif /* CTK_CONF_MOUSE_SUPPORT */
1419 
1420 #if CTK_CONF_SCREENSAVER
1421  ctk_signal_screensaver_start = process_alloc_event();
1422  ctk_signal_screensaver_stop = process_alloc_event();
1423 #endif /* CTK_CONF_SCREENSAVER */
1424 
1425  mode = CTK_MODE_NORMAL;
1426 
1427 #if CTK_CONF_ICONS
1428  iconx = ICONX_START;
1429  icony = ICONY_START;
1430 #endif /* CTK_CONF_ICONS */
1431 
1432 #if CTK_CONF_SCREENSAVER
1434 #endif /* CTK_CONF_SCREENSAVER */
1435 
1436  while(1) {
1437  process_poll(&ctk_process);
1439 
1440 #if CTK_CONF_SCREENSAVER
1441  if(timer_expired(&timer)) {
1442  timer_reset(&timer);
1443  handle_timer();
1444  }
1445 #endif /* CTK_CONF_SCREENSAVER */
1446 
1447 #if CTK_CONF_MENUS
1448  if(menus.open != NULL) {
1449  maxnitems = menus.open->nitems;
1450  } else {
1451  maxnitems = 0;
1452  }
1453 #endif /* CTK_CONF_MENUS */
1454 
1455 #if CTK_CONF_MOUSE_SUPPORT
1456  mouse_button_changed = mouse_moved = mouse_clicked = 0;
1457 
1458  /* See if there is any change in the buttons. */
1459  if(ctk_mouse_button() != mouse_button) {
1460  mouse_button = ctk_mouse_button();
1461  mouse_button_changed = 1;
1462  if(mouse_button == 0) {
1463  mouse_clicked = 1;
1464  }
1465  }
1466 
1467  /* Check if the mouse pointer has moved. */
1468  if(ctk_mouse_x() != mouse_x ||
1469  ctk_mouse_y() != mouse_y) {
1470  mouse_x = ctk_mouse_x();
1471  mouse_y = ctk_mouse_y();
1472  mouse_moved = 1;
1473  }
1474 
1475  mxc = ctk_mouse_xtoc(mouse_x);
1476  myc = ctk_mouse_ytoc(mouse_y);
1477 #endif /* CTK_CONF_MOUSE_SUPPORT */
1478 
1479 #if CTK_CONF_SCREENSAVER
1480  if(mode == CTK_MODE_SCREENSAVER) {
1481  if(ctk_arch_keyavail()
1482 #if CTK_CONF_MOUSE_SUPPORT
1483  || mouse_moved || mouse_button_changed
1484 #endif /* CTK_CONF_MOUSE_SUPPORT */
1485  ) {
1486  process_post(PROCESS_BROADCAST, ctk_signal_screensaver_stop, NULL);
1487  mode = CTK_MODE_NORMAL;
1488  }
1489  } else
1490 #endif /* CTK_CONF_SCREENSAVER */
1491  if(mode == CTK_MODE_NORMAL) {
1492 #if CTK_CONF_MOUSE_SUPPORT
1493  /* If there is any change in the mouse conditions, find out in
1494  which window the mouse pointer currently is in order to send
1495  the correct signals, or bring a window to focus. */
1496  if(mouse_moved || mouse_button_changed) {
1497  ctk_mouse_show();
1498 #if CTK_CONF_SCREENSAVER
1499  screensaver_timer = 0;
1500 #endif /* CTK_CONF_SCREENSAVER */
1501 
1502 #if CTK_CONF_MENUS
1503  if(myc == 0) {
1504  /* Here we should do whatever needs to be done when the mouse
1505  moves around and clicks in the menubar. */
1506  if(mouse_clicked) {
1507  static unsigned char titlelen;
1508 
1509  /* Find out which menu that the mouse pointer is in. Start
1510  with the ->next menu after the desktop menu. We assume
1511  that the menus start one character from the left screen
1512  side and that the desktop menu is farthest to the
1513  right. */
1514  menux = 1;
1515  for(menu = menus.menus->next;
1516  menu != NULL; menu = menu->next) {
1517  titlelen = menu->titlelen;
1518  if(mxc >= menux && mxc <= menux + titlelen) {
1519  break;
1520  }
1521  menux += titlelen;
1522  }
1523 
1524  /* Also check desktop menu. */
1525  if(mxc >= width - 7 &&
1526  mxc <= width - 1) {
1527  menu = &desktopmenu;
1528  }
1529 
1530  menus.open = menu;
1531  redraw |= REDRAW_MENUPART;
1532  }
1533  } else {
1534  --myc;
1535 
1536  if(menus.open != NULL) {
1537  static unsigned char nitems;
1538 
1539  /* Do whatever needs to be done when a menu is open. */
1540 
1541  /* First check if the mouse pointer is in the currently open
1542  menu. */
1543  if(menus.open == &desktopmenu) {
1544  menux = width - CTK_CONF_MENUWIDTH;
1545  } else {
1546  menux = 1;
1547  for(menu = menus.menus->next; menu != menus.open;
1548  menu = menu->next) {
1549  menux += menu->titlelen;
1550  }
1551  }
1552 
1553  nitems = menus.open->nitems;
1554  /* Find out which of the menu items the mouse is pointing
1555  to. */
1556  if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1557  if(myc <= nitems) {
1558  menus.open->active = myc;
1559  } else {
1560  menus.open->active = nitems - 1;
1561  }
1562  }
1563 
1564  if(mouse_clicked) {
1565  if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1566  myc <= nitems) {
1567  redraw |= activate_menu();
1568  } else {
1569  lastmenu = menus.open;
1570  menus.open = NULL;
1571  redraw |= REDRAW_MENUPART;
1572  }
1573  } else {
1574  redraw |= REDRAW_MENUS;
1575  }
1576  } else {
1577 #endif /* CTK_CONF_MENUS */
1578 
1579 #if CTK_CONF_WINDOWS
1580  /* Walk through the windows from top to bottom to see in
1581  which window the mouse pointer is. */
1582  if(dialog != NULL) {
1583  window = dialog;
1584  } else {
1585  for(window = windows; window != NULL;
1586  window = window->next) {
1587 
1588  /* Check if the mouse is within the window. */
1589  if(mxc >= window->x &&
1590  mxc <= window->x + window->w +
1591  2 * ctk_draw_windowborder_width &&
1592  myc >= window->y &&
1593  myc <= window->y + window->h +
1594  ctk_draw_windowtitle_height +
1595  ctk_draw_windowborder_height) {
1596  break;
1597  }
1598  }
1599  }
1600 
1601  /* If we didn't find any window, and there are no windows
1602  open, the mouse pointer will definately be within the
1603  background desktop window. */
1604  if(window == NULL) {
1605  window = &desktop_window;
1606  }
1607 
1608  /* If the mouse pointer moves around outside of the
1609  currently focused window (or dialog), we should not have
1610  any focused widgets in the focused window so we make sure
1611  that there are none. */
1612  if(windows != NULL &&
1613  window != windows &&
1614  windows->focused != NULL){
1615  unfocus_widget(windows->focused);
1616  }
1617 #endif /* CTK_CONF_WINDOWS */
1618 
1619  if(window != NULL) {
1620 #if CTK_CONF_WINDOWS
1621  /* If the mouse was clicked outside of the current window,
1622  we bring the clicked window to front. */
1623  if(dialog == NULL &&
1624  window != &desktop_window &&
1625  window != windows &&
1626  mouse_clicked) {
1627  /* Bring window to front. */
1628  ctk_window_open(window);
1629  redraw |= REDRAW_ALL;
1630  } else {
1631 
1632  /* Find out which widget currently is under the mouse
1633  pointer and give it focus, unless it already has
1634  focus. */
1635  mxc = mxc - window->x - ctk_draw_windowborder_width;
1636  myc = myc - window->y - ctk_draw_windowtitle_height;
1637 #endif /* CTK_CONF_WINDOWS */
1638 
1639  /* See if the mouse pointer is on a widget. If so, it
1640  should be selected and, if the button is clicked,
1641  activated. */
1642  for(widget = window->active; widget != NULL;
1643  widget = widget->next) {
1644 
1645  if(mxc >= widget->x &&
1646  mxc <= widget->x + widget->w + 1 &&
1647  myc >= widget->y &&
1648  myc <= widget->y + widget->h - 1) {
1649  break;
1650  }
1651  }
1652 
1653  /* if the mouse is moved in the focused window, we emit
1654  a ctk_signal_pointer_move signal to the owner of the
1655  window. */
1656  if(mouse_moved
1657 #if CTK_CONF_WINDOWS
1658  && (window != &desktop_window || windows == NULL)
1659 #endif /* CTK_CONF_WINDOWS */
1660  ) {
1661 
1662  process_post(window->owner, ctk_signal_pointer_move, NULL);
1663 
1664  /* If there was a focused widget that is not below the
1665  mouse pointer, we remove focus from the widget and
1666  redraw it. */
1667  if(window->focused != NULL &&
1668  widget != window->focused) {
1669  unfocus_widget(window->focused);
1670  }
1671  redraw |= REDRAW_WIDGETS;
1672  if(widget != NULL) {
1673  select_widget(widget);
1674  }
1675  }
1676 
1677  if(mouse_button_changed) {
1678  process_post(window->owner, ctk_signal_pointer_button,
1679  (process_data_t)(size_t)mouse_button);
1680  if(mouse_clicked && widget != NULL) {
1681  select_widget(widget);
1682  redraw |= activate(widget);
1683  }
1684  }
1685 #if CTK_CONF_WINDOWS
1686  }
1687 #endif /* CTK_CONF_WINDOWS */
1688  }
1689 #if CTK_CONF_MENUS
1690  }
1691  }
1692 #endif /* CTK_CONF_MENUS */
1693  }
1694 #endif /* CTK_CONF_MOUSE_SUPPORT */
1695 
1696  while(ctk_arch_keyavail()) {
1697 
1698  ctk_mouse_hide();
1699 
1700 #if CTK_CONF_SCREENSAVER
1701  screensaver_timer = 0;
1702 #endif /* CTK_CONF_SCREENSAVER */
1703 
1704  c = ctk_arch_getkey();
1705 
1706 #if CTK_CONF_WINDOWS
1707  if(dialog != NULL) {
1708  window = dialog;
1709  } else if(windows != NULL) {
1710  window = windows;
1711  } else {
1712  window = &desktop_window;
1713  }
1714 #else /* CTK_CONF_WINDOWS */
1715  if(window == NULL) {
1716  continue;
1717  }
1718 #endif /* CTK_CONF_WINDOWS */
1719 
1720  /* Allow to exit the process owning the foreground window by
1721  pressing ctrl-c. This is especially useful if there's no
1722  closebutton on the window frames (or no windows at all).
1723  */
1724  if(c == 3) {
1725  process_post(window->owner, PROCESS_EVENT_EXIT, NULL);
1726  }
1727 
1728  widget = window->focused;
1729 
1730  if(widget != NULL &&
1731  widget->type == CTK_WIDGET_TEXTENTRY &&
1732  widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1733  textentry_input(c, (struct ctk_textentry *)widget);
1734  add_redrawwidget(widget);
1735 #if CTK_CONF_MENUS
1736  } else if(menus.open != NULL) {
1737  redraw |= menus_input(c);
1738 #endif /* CTK_CONF_MENUS */
1739  } else {
1740  switch(c) {
1741  case CTK_CONF_WIDGETDOWN_KEY:
1742  switch_focus_widget(DOWN);
1743  break;
1744  case CTK_CONF_WIDGETUP_KEY:
1745  switch_focus_widget(UP);
1746  break;
1747 #if CTK_CONF_MENUS
1748  case CTK_CONF_MENU_KEY:
1749  if(dialog == NULL) {
1750  if(lastmenu == NULL) {
1751  menus.open = menus.menus;
1752  } else {
1753  menus.open = lastmenu;
1754  }
1755  menus.open->active = 0;
1756  redraw |= REDRAW_MENUS;
1757  }
1758  break;
1759 #endif /* CTK_CONF_MENUS */
1760 #if CTK_CONF_WINDOWS
1761  case CTK_CONF_WINDOWSWITCH_KEY:
1762  if(windows != NULL) {
1763  for(window = windows; window->next != NULL;
1764  window = window->next);
1765  ctk_window_open(window);
1766  }
1767  break;
1768 #endif /* CTK_CONF_WINDOWS */
1769  default:
1770 
1771  if(c == CH_ENTER &&
1772  widget != NULL) {
1773  redraw |= activate(widget);
1774  } else {
1775  if(widget != NULL &&
1776  widget->type == CTK_WIDGET_TEXTENTRY) {
1777  if(widget->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1778  widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1779  textentry_input(0, (struct ctk_textentry *)widget);
1780  }
1781  textentry_input(c, (struct ctk_textentry *)widget);
1782  add_redrawwidget(widget);
1783  } else {
1784  unfocus_widget(window->focused);
1786  (process_data_t)(size_t)c);
1787  }
1788  }
1789  break;
1790  }
1791  }
1792 
1793 #if 0
1794  if(redraw & REDRAW_WIDGETS) {
1795  widgetptr = redraw_widgets;
1796  for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1797  widget_redraw(*widgetptr);
1798  *widgetptr = NULL;
1799  ++widgetptr;
1800  }
1801  redraw &= ~REDRAW_WIDGETS;
1802  redraw_widgetptr = 0;
1803  }
1804 #endif /* 0 */
1805  }
1806 #if CTK_CONF_WINDOWMOVE
1807  } else if(mode == CTK_MODE_WINDOWMOVE) {
1808 
1809  redraw = 0;
1810 
1811  window = windows;
1812 
1813 #if CTK_CONF_MOUSE_SUPPORT
1814 
1815  /* If the mouse has moved, we move the window as well. */
1816  if(mouse_moved) {
1817 
1818  if(window->w + mxc + 2 >= width) {
1819  window->x = width - 2 - window->w;
1820  } else {
1821  window->x = mxc;
1822  }
1823 
1824  if(window->h + myc + ctk_draw_windowtitle_height +
1825  ctk_draw_windowborder_height >= height) {
1826  window->y = height - window->h -
1827  ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
1828  } else {
1829  window->y = myc;
1830  }
1831 #if CTK_CONF_MENUS
1832  if(window->y > 0) {
1833  --window->y;
1834  }
1835 #endif /* CTK_CONF_MENUS */
1836 
1837  redraw = REDRAW_ALL;
1838  }
1839 
1840  /* Check if the mouse has been clicked, and stop moving the window
1841  if so. */
1842  if(mouse_button_changed &&
1843  mouse_button == 0) {
1844  mode = CTK_MODE_NORMAL;
1845  redraw = REDRAW_ALL;
1846  }
1847 #endif /* CTK_CONF_MOUSE_SUPPORT */
1848 
1849  while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1850 
1851 #if CTK_CONF_SCREENSAVER
1852  screensaver_timer = 0;
1853 #endif /* CTK_CONF_SCREENSAVER */
1854 
1855  c = ctk_arch_getkey();
1856 
1857  switch(c) {
1858  case CH_CURS_RIGHT:
1859  ++window->x;
1860  if(window->x + window->w + 1 >= width) {
1861  --window->x;
1862  }
1863  redraw = REDRAW_ALL;
1864  break;
1865  case CH_CURS_LEFT:
1866  if(window->x > 0) {
1867  --window->x;
1868  }
1869  redraw = REDRAW_ALL;
1870  break;
1871  case CH_CURS_DOWN:
1872  ++window->y;
1873  if(window->y + window->h + 1 + CTK_CONF_MENUS >= height) {
1874  --window->y;
1875  }
1876  redraw = REDRAW_ALL;
1877  break;
1878  case CH_CURS_UP:
1879  if(window->y > 0) {
1880  --window->y;
1881  }
1882  redraw = REDRAW_ALL;
1883  break;
1884  default:
1885  mode = CTK_MODE_NORMAL;
1886  redraw = REDRAW_ALL;
1887  break;
1888  }
1889  }
1890 #endif /* CTK_CONF_WINDOWMOVE */
1891  }
1892 
1893  if(redraw & REDRAW_ALL) {
1894  do_redraw_all(CTK_CONF_MENUS, height);
1895 #if CTK_CONF_MENUS
1896  } else if(redraw & REDRAW_MENUPART) {
1897  do_redraw_all(CTK_CONF_MENUS, maxnitems + 1);
1898  } else if(redraw & REDRAW_MENUS) {
1899  ctk_draw_menus(&menus);
1900 #endif /* CTK_CONF_MENUS */
1901  } else if(redraw & REDRAW_FOCUS) {
1902 #if CTK_CONF_WINDOWS
1903  if(dialog != NULL) {
1904  ctk_window_redraw(dialog);
1905  } else if(windows != NULL) {
1906  ctk_window_redraw(windows);
1907  } else {
1908  ctk_window_redraw(&desktop_window);
1909  }
1910 #else /* CTK_CONF_WINDOWS */
1911  if(window != NULL) {
1912  ctk_window_redraw(window);
1913  }
1914 #endif /* CTK_CONF_WINDOWS */
1915  } else if(redraw & REDRAW_WIDGETS) {
1916  widgetptr = redraw_widgets;
1917  for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1918  widget_redraw(*widgetptr);
1919  *widgetptr = NULL;
1920  ++widgetptr;
1921  }
1922  }
1923  redraw = 0;
1924  redraw_widgetptr = 0;
1925  }
1926 
1927  PROCESS_END();
1928 }
1929 /*---------------------------------------------------------------------------*/
1930 /** @} */
1931 /** @} */
#define PROCESS_CURRENT()
Get a pointer to the currently running process.
Definition: process.h:402
#define CTK_WIDGET_ADD(win, widg)
Add a widget to a window.
Definition: ctk.h:752
process_event_t ctk_signal_window_close
Emitted when a window is closed.
Definition: ctk.c:155
#define CTK_WIDGET_TEXTENTRY
Widget number: The CTK textentry widget.
Definition: ctk.h:72
char ctk_arch_key_t
The keyboard character type of the system.
Definition: ctk-conio.h:40
void ctk_mode_set(unsigned char m)
Sets the current CTK mode.
Definition: ctk.c:280
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
struct ctk_window * next
The next window in the doubly linked list of open windows.
Definition: ctk.h:507
Representation of the menu bar.
Definition: ctk.h:611
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
unsigned char w
The width of the window, excluding window borders.
Definition: ctk.h:549
A timer.
Definition: timer.h:86
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
struct ctk_menu * menus
A pointer to a linked list of all menus, including the open menu and the desktop menu.
Definition: ctk.h:612
void ctk_window_close(struct ctk_window *w)
Close a window if it is open.
Definition: ctk.c:400
struct ctk_widget * next
The next widget in the linked list of widgets that is contained in the ctk_window structure...
Definition: ctk.h:445
process_event_t ctk_signal_widget_select
Emitted when a widget is selected.
Definition: ctk.c:126
struct ctk_widget * inactive
The list if widgets that cannot be selected by the user.
Definition: ctk.h:554
unsigned char active
The currently active menu item.
Definition: ctk.h:601
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
process_event_t ctk_signal_hyperlink_hover
Same as ctk_signal_widget_select.
Definition: ctk.c:126
void process_post_synch(struct process *p, process_event_t ev, process_data_t data)
Post a synchronous event to a process.
Definition: process.c:362
void ctk_menu_add(struct ctk_menu *menu)
Add a menu to the menu bar.
Definition: ctk.c:504
void ctk_draw_clear(unsigned char y1, unsigned char y2)
Clear the screen between the clip bounds.
Definition: ctk-conio.c:441
unsigned char x
The x position of the widget within the containing window, in character coordinates.
Definition: ctk.h:452
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
struct ctk_menuitem items[CTK_MAXMENUITEMS]
The array which contains all the menu items.
Definition: ctk.h:603
void CC_FASTCALL ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window, CC_REGISTER_ARG struct ctk_widget *widget)
Adds a widget to a window.
Definition: ctk.c:925
#define CTK_FOCUS_WINDOW
Widget focus flag: widget&#39;s window is the foremost one.
Definition: ctk.h:990
unsigned char ctk_desktop_width(struct ctk_desktop *d)
Gets the width of the desktop.
Definition: ctk.c:950
unsigned char nitems
The total number of menu items in the menu.
Definition: ctk.h:599
#define NULL
The null pointer.
void ctk_draw_widget(struct ctk_widget *w, unsigned char focus, unsigned char clipy1, unsigned char clipy2)
Draw a widget on a window.
Definition: ctk-conio.c:239
void ctk_window_redraw(struct ctk_window *w)
Redraw a window.
Definition: ctk.c:652
void ctk_widget_redraw(struct ctk_widget *widget)
Redraws a widget.
Definition: ctk.c:902
struct ctk_menu * next
Apointer to the next menu, or is NULL if this is the last menu, and should be used by the ctk-draw mo...
Definition: ctk.h:587
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
unsigned char type
The type of the widget: CTK_WIDGET_SEPARATOR, CTK_WIDGET_LABEL, CTK_WIDGET_BUTTON, CTK_WIDGET_HYPERLINK, CTK_WIDGET_TEXTENTRY, CTK_WIDGET_BITMAP or CTK_WIDGET_ICON.
Definition: ctk.h:456
void ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, struct process *p)
Add an icon to the desktop.
Definition: ctk.c:304
process_event_t ctk_signal_menu_activate
Emitted when a menu item is activated.
Definition: ctk.c:151
void ctk_draw_window(struct ctk_window *window, unsigned char focus, unsigned char clipy1, unsigned char clipy2, unsigned char draw_borders)
Draw a window onto the screen.
Definition: ctk-conio.c:327
unsigned char y
The y position of the widget within the containing window, in character coordinates.
Definition: ctk.h:452
#define CTK_WIDGET_SEPARATOR
Widget number: The CTK separator widget.
Definition: ctk.h:64
struct ctk_window * prev
The previous window in the doubly linked list of open windows.
Definition: ctk.h:507
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
unsigned char ctk_arch_keyavail(void)
Check if there is a keypress in the keyboard input queue.
Definition: ctk-curses.c:464
process_event_t ctk_signal_keypress
Emitted for every key being pressed.
Definition: ctk.c:126
#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
void ctk_window_new(struct ctk_window *window, unsigned char w, unsigned char h, char *title)
Create a new window.
Definition: ctk.c:732
process_event_t ctk_signal_button_hover
Same as ctk_signal_widget_select.
Definition: ctk.c:126
unsigned char ctk_mode_get(void)
Retrieves the current CTK mode.
Definition: ctk.c:291
char * title
The title of the window.
Definition: ctk.h:520
struct ctk_widget * focused
A pointer to the widget on the active list that is currently selected, or NULL if no widget is select...
Definition: ctk.h:562
#define CTK_FOCUS_DIALOG
Widget focus flag: widget is in a dialog.
Definition: ctk.h:992
void ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu, char *title)
Creates a new menu.
Definition: ctk.c:775
struct process * owner
The process that owns the window.
Definition: ctk.h:515
void ctk_menu_remove(struct ctk_menu *menu)
Remove a menu from the menu bar.
Definition: ctk.c:532
void ctk_window_clear(struct ctk_window *w)
Remove all widgets from a window.
Definition: ctk.c:485
process_event_t ctk_signal_hyperlink_activate
Emitted when a hyperlink is activated.
Definition: ctk.c:126
#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
#define CTK_WIDGET_BUTTON
Widget number: The CTK button widget.
Definition: ctk.h:68
unsigned char ctk_desktop_height(struct ctk_desktop *d)
Gets the height of the desktop.
Definition: ctk.c:965
process_event_t ctk_signal_widget_activate
Emitted when a widget is activated (pressed).
Definition: ctk.c:126
#define CC_REGISTER_ARG
Configure if the C compiler supports the &quot;register&quot; keyword for function arguments.
Definition: cc.h:57
ctk_arch_key_t ctk_arch_getkey(void)
Get a keypress from the keyboard input queue.
Definition: ctk-curses.c:452
union ctk_widget::@20 widget
The union which contains the actual widget structure, as determined by the type field.
CTK screen drawing module interface, ctk-draw.
Representation of an individual menu.
Definition: ctk.h:586
void ctk_draw_init(void)
The initialization function.
Definition: ctk-conio.c:74
void ctk_draw_dialog(struct ctk_window *dialog)
Draw a dialog onto the screen.
#define CTK_WIDGET_HYPERLINK
Widget number: The CTK hyperlink widget.
Definition: ctk.h:70
Representation of a CTK window.
Definition: ctk.h:506
struct ctk_window * window
The window in which the widget is contained.
Definition: ctk.h:448
#define CTK_FOCUS_WIDGET
Widget focus flag: widget has focus.
Definition: ctk.h:988
#define CTK_WIDGET_LABEL
Widget number: The CTK label widget.
Definition: ctk.h:66
void ctk_draw_clear_window(struct ctk_window *window, unsigned char focus, unsigned char clipy1, unsigned char clipy2)
Draw the window background.
Definition: ctk-conio.c:265
The generic CTK widget structure that contains all other widget structures.
Definition: ctk.h:444
unsigned char w
The width of the widget in character coordinates.
Definition: ctk.h:464
#define CC_FASTCALL
Configure if the C compiler supports fastcall function declarations.
Definition: cc.h:77
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:121
unsigned char h
The height of the window, excluding window borders.
Definition: ctk.h:549
char * title
The menu items text.
Definition: ctk.h:572
unsigned char titlelen
The length of the title in characters.
Definition: ctk.h:593
#define CTK_WIDGET_TYPE(w)
Obtain the type of a widget.
Definition: ctk.h:780
struct ctk_widget * active
The list of widgets that can be selected by the user.
Definition: ctk.h:558
CTK header file.
#define CTK_WIDGET_ICON
Widget number: The CTK icon widget.
Definition: ctk.h:76
void timer_reset(struct timer *t)
Reset the timer with the same interval.
Definition: timer.c:84
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
unsigned char h
The height of the widget in character coordinates.
Definition: ctk.h:464