blob: 4ad88df290a98fb24b677afdb892006f11634b84 [file] [log] [blame]
adamdunkels35298692003-08-31 22:16:49 +00001/**
adamdunkelse937ded2003-10-01 07:53:57 +00002 * \defgroup ctk The CTK graphical user interface.
3 * @{
adamdunkels35298692003-08-31 22:16:49 +00004 * The Contiki Toolkit (CTK) provides the graphical user interface for
5 * the Contiki system.
6 *
adamdunkelse937ded2003-10-01 07:53:57 +00007 */
8
9/**
10 * \file
11 * The Contiki Toolkit CTK, the Contiki GUI.
12 * \author Adam Dunkels <adam@dunkels.com>
adamdunkels35298692003-08-31 22:16:49 +000013 */
14
adamdunkelsca9ddcb2003-03-19 14:13:31 +000015/*
adamdunkels35298692003-08-31 22:16:49 +000016 * Copyright (c) 2002-2003, Adam Dunkels.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000017 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above
25 * copyright notice, this list of conditions and the following
26 * disclaimer in the documentation and/or other materials provided
27 * with the distribution.
adamdunkels35298692003-08-31 22:16:49 +000028 * 3. The name of the author may not be used to endorse or promote
adamdunkelsca9ddcb2003-03-19 14:13:31 +000029 * products derived from this software without specific prior
30 * written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
33 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
40 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
adamdunkels3b548c82004-07-04 11:41:39 +000044 * This file is part of the Contiki operating system.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000045 *
adamdunkels3b548c82004-07-04 11:41:39 +000046 * $Id: ctk.c,v 1.39 2004/07/04 11:41:39 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000047 *
48 */
49
50#include "ek.h"
adamdunkels3b548c82004-07-04 11:41:39 +000051#include "cc.h"
52
adamdunkelsca9ddcb2003-03-19 14:13:31 +000053#include "ctk.h"
54#include "ctk-draw.h"
55#include "ctk-conf.h"
adamdunkelsc4902862003-04-09 00:30:45 +000056#include "ctk-mouse.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000057
adamdunkels3b548c82004-07-04 11:41:39 +000058#include "timer.h"
59
adamdunkels591724c2003-08-01 00:07:19 +000060#include <string.h>
61
adamdunkelsca9ddcb2003-03-19 14:13:31 +000062static unsigned char height, width;
63
64static unsigned char mode;
65
66static struct ctk_window desktop_window;
67static struct ctk_window *windows;
68static struct ctk_window *dialog;
69
70#if CTK_CONF_MENUS
71static struct ctk_menus menus;
72static struct ctk_menu *lastmenu;
73static struct ctk_menu desktopmenu;
74#endif /* CTK_CONF_MENUS */
75
76#ifndef NULL
77#define NULL (void *)0
78#endif /* NULL */
79
adamdunkelsca9ddcb2003-03-19 14:13:31 +000080#define REDRAW_NONE 0
81#define REDRAW_ALL 1
82#define REDRAW_FOCUS 2
83#define REDRAW_WIDGETS 4
84#define REDRAW_MENUS 8
85#define REDRAW_MENUPART 16
86
87#define MAX_REDRAWWIDGETS 4
88static unsigned char redraw;
89static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
90static unsigned char redraw_widgetptr;
91static unsigned char maxnitems;
92
93static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000094#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000095#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000096#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000097#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000098#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000099
adamdunkels3b548c82004-07-04 11:41:39 +0000100#ifndef ctk_arch_isprint
101unsigned char ctk_arch_isprint(char c);
102#endif /* ctk_arch_isprint */
103
104EK_POLLHANDLER(ctk_poll);
105EK_EVENTHANDLER(ctk_eventhandler, ev, data);
106EK_PROCESS(p, "CTK Contiki GUI", EK_PRIO_NORMAL, ctk_eventhandler,
107 ctk_poll, NULL);
108/*static struct ek_proc p =
109 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000110static ek_id_t ctkid;
111
adamdunkelse937ded2003-10-01 07:53:57 +0000112/** @} */
113
114/**
115 * \addtogroup signals System signals
116 * @{
117 */
adamdunkels3b548c82004-07-04 11:41:39 +0000118ek_event_t
adamdunkels35298692003-08-31 22:16:49 +0000119
adamdunkelse937ded2003-10-01 07:53:57 +0000120 /**
121 * Emitted for every key being pressed.
122 *
123 * The key is passed as signal data.*/
adamdunkels35298692003-08-31 22:16:49 +0000124 ctk_signal_keypress,
125
126 /** Emitted when a widget is activated (pressed). A pointer to the
127 widget is passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000128 ctk_signal_widget_activate,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000129
adamdunkelse937ded2003-10-01 07:53:57 +0000130 /** Same as ctk_signal_widget_activate. */
adamdunkels35298692003-08-31 22:16:49 +0000131 ctk_signal_button_activate,
132
133 /** Emitted when a widget is selected. A pointer to the widget is
134 passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000135 ctk_signal_widget_select,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000136
adamdunkelse937ded2003-10-01 07:53:57 +0000137 /** Same as ctk_signal_widget_select. */
adamdunkels35298692003-08-31 22:16:49 +0000138 ctk_signal_button_hover,
139
140 /** Emitted when a hyperlink is activated. The signal is broadcast
141 to all listeners. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000142 ctk_signal_hyperlink_activate,
adamdunkels35298692003-08-31 22:16:49 +0000143
adamdunkelse937ded2003-10-01 07:53:57 +0000144 /** Same as ctk_signal_widget_select. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000145 ctk_signal_hyperlink_hover,
adamdunkels35298692003-08-31 22:16:49 +0000146
147 /** Emitted when a menu item is activated. The number of the menu
148 item is passed as signal data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000149 ctk_signal_menu_activate,
adamdunkels35298692003-08-31 22:16:49 +0000150
151 /** Emitted when a window is closed. A pointer to the window is
152 passed as signal data. */
adamdunkelsc4902862003-04-09 00:30:45 +0000153 ctk_signal_window_close,
adamdunkels35298692003-08-31 22:16:49 +0000154
155 /** Emitted when the mouse pointer is moved. A NULL pointer is
156 passed as signal data and it is up to the listening process to
157 check the position of the mouse using the CTK mouse API.*/
adamdunkelsc4902862003-04-09 00:30:45 +0000158 ctk_signal_pointer_move,
adamdunkels35298692003-08-31 22:16:49 +0000159
160 /** Emitted when a mouse button is pressed. The button is passed as
161 signal data to the listening process. */
adamdunkelsb2486562003-04-11 20:22:03 +0000162 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000163
adamdunkels66109622003-04-24 17:17:10 +0000164#if CTK_CONF_SCREENSAVER
adamdunkelse937ded2003-10-01 07:53:57 +0000165/** Emitted when the user has been idle long enough for the
166 screensaver to start. */
adamdunkels3b548c82004-07-04 11:41:39 +0000167ek_event_t ctk_signal_screensaver_stop,
adamdunkelse937ded2003-10-01 07:53:57 +0000168 /** Emitted when the user presses a key or moves the mouse when the
169 screensaver is active. */
adamdunkels9795b2e2003-08-09 23:32:37 +0000170 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000171#endif /* CTK_CONF_SCREENSAVER */
172
adamdunkelse937ded2003-10-01 07:53:57 +0000173/** @} */
174
175/**
176 * \addtogroup ctk
177 * @{
178 */
adamdunkels66109622003-04-24 17:17:10 +0000179
adamdunkels19a787c2003-04-09 09:22:24 +0000180#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000181unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000182#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000183
adamdunkels9795b2e2003-08-09 23:32:37 +0000184static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000185unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels3b548c82004-07-04 11:41:39 +0000186/*static ek_clock_t start, current;*/
187static struct timer timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000188
189#if CTK_CONF_MENUS
190/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000191/**
192 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000193 *
194 * Creates the leftmost menu, "Desktop". Since the desktop menu
195 * contains the list of all open windows, this function will be called
196 * whenever a window is opened or closed.
197 */
adamdunkels35298692003-08-31 22:16:49 +0000198/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000199static void
200make_desktopmenu(void)
201{
202 struct ctk_window *w;
203
204 desktopmenu.nitems = 0;
205
206 if(windows == NULL) {
207 ctk_menuitem_add(&desktopmenu, "(No windows)");
208 } else {
209 for(w = windows; w != NULL; w = w->next) {
210 ctk_menuitem_add(&desktopmenu, w->title);
211 }
212 }
213}
214#endif /* CTK_CONF_MENUS */
215/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000216/**
217 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000218 *
adamdunkels35298692003-08-31 22:16:49 +0000219 * This function must be called before any other CTK function, but
220 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000221 */
adamdunkels35298692003-08-31 22:16:49 +0000222/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000223void
224ctk_init(void)
225{
adamdunkels3b548c82004-07-04 11:41:39 +0000226 ctkid = ek_start(&p);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227
228 windows = NULL;
229 dialog = NULL;
230
231#if CTK_CONF_MENUS
232 ctk_menu_new(&desktopmenu, "Desktop");
233 make_desktopmenu();
234 menus.menus = menus.desktopmenu = &desktopmenu;
235#endif /* CTK_CONF_MENUS */
236
adamdunkelsb2486562003-04-11 20:22:03 +0000237#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000238 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000239 ctk_mouse_show();
240#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000241
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000242 ctk_draw_init();
243
244 height = ctk_draw_height();
245 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000246
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000247 desktop_window.active = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000248 desktop_window.owner = ctkid;
adamdunkelsb2486562003-04-11 20:22:03 +0000249
adamdunkels3b548c82004-07-04 11:41:39 +0000250 ctk_signal_keypress = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000251
252 ctk_signal_button_activate =
adamdunkels3b548c82004-07-04 11:41:39 +0000253 ctk_signal_widget_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000254
255 ctk_signal_button_hover =
256 ctk_signal_hyperlink_hover =
adamdunkels3b548c82004-07-04 11:41:39 +0000257 ctk_signal_widget_select = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000258
adamdunkels3b548c82004-07-04 11:41:39 +0000259 ctk_signal_hyperlink_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000260
adamdunkels3b548c82004-07-04 11:41:39 +0000261 ctk_signal_menu_activate = ek_alloc_event();
262 ctk_signal_window_close = ek_alloc_event();
adamdunkelsc4902862003-04-09 00:30:45 +0000263
adamdunkels3b548c82004-07-04 11:41:39 +0000264 ctk_signal_pointer_move = ek_alloc_event();
265 ctk_signal_pointer_button = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000266
267
268#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +0000269 ctk_signal_screensaver_start = ek_alloc_event();
270 ctk_signal_screensaver_stop = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000271#endif /* CTK_CONF_SCREENSAVER */
272
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000273
274 mode = CTK_MODE_NORMAL;
275
276 iconx = ICONX_START;
277 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000278
279 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000280
adamdunkels3b548c82004-07-04 11:41:39 +0000281 /* start = ek_clock();*/
282 timer_set(&timer, CLOCK_SECOND);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000283}
adamdunkelse937ded2003-10-01 07:53:57 +0000284
285/**
286 * \addtogroup ctkappfunc
287 * @{
288 */
289
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000290/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000291/**
292 * Sets the current CTK mode.
293 *
294 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
295 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
296 * keypresses and mouse pointer movements are processed and the screen
297 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
298 * performed and the first key press or pointer movement will cause
299 * the ctk_signal_screensaver_stop to be emitted. In the
300 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
301 * ignored and no screen redraws are made.
302 *
303 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000304 */
adamdunkels35298692003-08-31 22:16:49 +0000305/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000306void
307ctk_mode_set(unsigned char m) {
308 mode = m;
309}
310/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000311/**
312 * Retrieves the current CTK mode.
313 *
314 * \return The current CTK mode.
315 */
316/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000317unsigned char
318ctk_mode_get(void) {
319 return mode;
320}
321/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000322/**
323 * Add an icon to the desktop.
324 *
325 * \param icon The icon to be added.
adamdunkels0404ef12003-09-04 19:36:04 +0000326 *
327 * \param id The process ID of the process that owns the icon.
adamdunkels35298692003-08-31 22:16:49 +0000328 */
329/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000330void
adamdunkels0404ef12003-09-04 19:36:04 +0000331ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, ek_id_t id)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000332{
adamdunkels0404ef12003-09-04 19:36:04 +0000333#if CTK_CONF_ICONS
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000334 icon->x = iconx;
335 icon->y = icony;
adamdunkels0404ef12003-09-04 19:36:04 +0000336 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000337
338 icony += ICONY_DELTA;
339 if(icony >= ICONY_MAX) {
340 icony = ICONY_START;
341 iconx += ICONX_DELTA;
342 }
343
344 ctk_widget_add(&desktop_window, icon);
345#endif /* CTK_CONF_ICONS */
346}
347/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000348/**
349 * Open a dialog box.
350 *
351 * \param d The dialog to be opened.
352 */
353/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000354void
355ctk_dialog_open(struct ctk_window *d)
356{
357 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000358 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000359}
360/*-----------------------------------------------------------------------------------*/
361/**
362 * Close the dialog box, if one is open.
363 *
364 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000365/*-----------------------------------------------------------------------------------*/
366void
367ctk_dialog_close(void)
368{
369 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000370 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000371}
372/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000373/**
374 * Open a window, or bring window to front if already open.
375 *
376 * \param w The window to be opened.
377 */
378/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000379void
adamdunkelsd07a5422003-04-05 12:22:35 +0000380ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000381{
382 struct ctk_window *w2;
383
384 /* Check if already open. */
385 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
386 if(w2 == NULL) {
387 /* Not open, so we add it at the head of the list of open
388 windows. */
389 w->next = windows;
390 if(windows != NULL) {
391 windows->prev = w;
392 }
393 windows = w;
394 w->prev = NULL;
395 } else {
396 /* Window already open, so we move it to the front of the windows
397 list. */
398 if(w != windows) {
399 if(w->next != NULL) {
400 w->next->prev = w->prev;
401 }
402 if(w->prev != NULL) {
403 w->prev->next = w->next;
404 }
405 w->next = windows;
406 windows->prev = w;
407 windows = w;
408 w->prev = NULL;
409 }
410 }
411
412#if CTK_CONF_MENUS
413 /* Recreate the Desktop menu's window entries.*/
414 make_desktopmenu();
415#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000416
417 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000418}
419/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000420/**
421 * Close a window if it is open.
422 *
423 * If the window is not open, this function does nothing.
424 *
425 * \param w The window to be closed.
426 */
427/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000428void
429ctk_window_close(struct ctk_window *w)
430{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000431 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000432
433 if(w == NULL) {
434 return;
435 }
436
437 /* Check if the window to be closed is the first window on the
438 list. */
439 if(w == windows) {
440 windows = w->next;
441 if(windows != NULL) {
442 windows->prev = NULL;
443 }
444 w->next = w->prev = NULL;
445 } else {
446 /* Otherwise we step through the list until we find the window
447 before the one to be closed. We then redirect its ->next
448 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000449 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
450
451 if(w2 == NULL) {
452 /* The window wasn't open, so there is nothing more for us to
453 do. */
454 return;
455 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000456
457 if(w->next != NULL) {
458 w->next->prev = w->prev;
459 }
460 w2->next = w->next;
461
462 w->next = w->prev = NULL;
463 }
464
465#if CTK_CONF_MENUS
466 /* Recreate the Desktop menu's window entries.*/
467 make_desktopmenu();
468#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000469 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000470}
471/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000472/**
473 * \internal Create the move and close buttons on the window titlebar.
474 */
475/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000476static void
477make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000478{
adamdunkels3b548c82004-07-04 11:41:39 +0000479 unsigned char placement;
480
481 if(ctk_draw_windowtitle_height >= 2) {
482 placement = -1 - ctk_draw_windowtitle_height/2;
483 } else {
484 placement = -1;
485 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000486#if CTK_CONF_WINDOWMOVE
adamdunkels3b548c82004-07-04 11:41:39 +0000487 CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
488 window->titlelen, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000489#else
adamdunkels3b548c82004-07-04 11:41:39 +0000490 CTK_LABEL_NEW(&window->titlebutton, 0, placement,
491 window->titlelen, 1, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000492#endif /* CTK_CONF_WINDOWMOVE */
493 CTK_WIDGET_ADD(window, &window->titlebutton);
494
495
496#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +0000497 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, placement,
498 1, "x");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000499#else
adamdunkels3b548c82004-07-04 11:41:39 +0000500 CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
501 3, 1, " ");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000502#endif /* CTK_CONF_WINDOWCLOSE */
503 CTK_WIDGET_ADD(window, &window->closebutton);
504}
505/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000506/**
507 * Remove all widgets from a window.
508 *
509 * \param w The window to be cleared.
510 */
511/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000512void
adamdunkels35298692003-08-31 22:16:49 +0000513ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000514{
adamdunkels35298692003-08-31 22:16:49 +0000515 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000516
adamdunkels35298692003-08-31 22:16:49 +0000517 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000518}
519/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000520/**
521 * Add a menu to the menu bar.
522 *
523 * \param menu The menu to be added.
524 *
525 * \note Do not call this function multiple times for the same menu,
526 * as no check is made to see if the menu already is in the menu bar.
527 */
528/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529void
530ctk_menu_add(struct ctk_menu *menu)
531{
532#if CTK_CONF_MENUS
533 struct ctk_menu *m;
534
535 if(lastmenu == NULL) {
536 lastmenu = menu;
537 }
538
539 for(m = menus.menus; m->next != NULL; m = m->next) {
540 if(m == menu) {
541 return;
542 }
543 }
544 m->next = menu;
545 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000546
547 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000548#endif /* CTK_CONF_MENUS */
549}
550/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000551/**
552 * Remove a menu from the menu bar.
553 *
554 * \param menu The menu to be removed.
555 */
556/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000557void
558ctk_menu_remove(struct ctk_menu *menu)
559{
560#if CTK_CONF_MENUS
561 struct ctk_menu *m;
562
563 for(m = menus.menus; m->next != NULL; m = m->next) {
564 if(m->next == menu) {
565 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000566 if(menu == lastmenu) {
567 lastmenu = NULL;
568 }
569 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000570 return;
571 }
572 }
573#endif /* CTK_CONF_MENUS */
574}
575/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000576/**
577 * \internal Redraws everything on the screen within the clip
578 * interval.
579 *
580 * \param clipy1 The upper bound of the clip interval
581 * \param clipy2 The lower bound of the clip interval
582 */
583/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000584static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000585do_redraw_all(unsigned char clipy1, unsigned char clipy2)
586{
587 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000588 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000589
590 if(mode != CTK_MODE_NORMAL &&
591 mode != CTK_MODE_WINDOWMOVE) {
592 return;
593 }
594
595 ctk_draw_clear(clipy1, clipy2);
596
597 /* Draw widgets in root window */
598 for(widget = desktop_window.active;
599 widget != NULL; widget = widget->next) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000600 ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000601 }
602
603 /* Draw windows */
604 if(windows != NULL) {
605 /* Find the last window.*/
606 for(w = windows; w->next != NULL; w = w->next);
607
608 /* Draw the windows from back to front. */
609 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000610 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000611 ctk_draw_window(w, 0, clipy1, clipy2);
612 }
613 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000614 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000615 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
616 }
617
618 /* Draw dialog (if any) */
619 if(dialog != NULL) {
620 ctk_draw_dialog(dialog);
621 }
622
623#if CTK_CONF_MENUS
624 ctk_draw_menus(&menus);
625#endif /* CTK_CONF_MENUS */
626}
627/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000628/**
629 * Redraw the entire desktop.
630 *
631 * \param d The desktop to be redrawn.
632 *
633 * \note Currently the parameter d is not used, but must be set to
634 * NULL.
adamdunkelse937ded2003-10-01 07:53:57 +0000635 *
adamdunkels35298692003-08-31 22:16:49 +0000636 */
637/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000638void
adamdunkels965e2922003-06-30 20:44:57 +0000639ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000640{
adamdunkels3b548c82004-07-04 11:41:39 +0000641 if(EK_CURRENT() == &p) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000642 if(mode == CTK_MODE_NORMAL ||
643 mode == CTK_MODE_WINDOWMOVE) {
644 do_redraw_all(1, height);
645 }
646 } else {
647 redraw |= REDRAW_ALL;
648 }
649}
650/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000651/**
652 * Redraw a window.
653 *
654 * This function redraws the window, but only if it is the foremost
655 * one on the desktop.
656 *
657 * \param w The window to be redrawn.
658 */
659/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000660void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000661ctk_window_redraw(struct ctk_window *w)
662{
663 /* Only redraw the window if it is a dialog or if it is the foremost
664 window. */
665 if(mode != CTK_MODE_NORMAL) {
666 return;
667 }
668
669 if(w == dialog) {
670 ctk_draw_dialog(w);
671 } else if(dialog == NULL &&
672#if CTK_CONF_MENUS
673 menus.open == NULL &&
674#endif /* CTK_CONF_MENUS */
675 windows == w) {
676 ctk_draw_window(w, CTK_FOCUS_WINDOW,
677 0, height);
678 }
679}
680/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000681/**
682 * \internal Creates a new window.
683 *
684 * \param window The window to be created.
685 * \param w The width of the window.
686 * \param h The height of the window.
687 * \param title The title of the window.
688 */
689/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000690static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000691window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000692 unsigned char w, unsigned char h,
693 char *title)
694{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000695
696 if(w >= width - 2) {
697 window->x = 0;
698 } else {
699 window->x = (width - w - 2) / 2;
700 }
701 if(h >= height - 3) {
702 window->y = 0;
703 } else {
adamdunkels3b548c82004-07-04 11:41:39 +0000704 window->y = (height - h - ctk_draw_windowtitle_height) / 2;
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000705 }
706
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000707 window->w = w;
708 window->h = h;
709 window->title = title;
710 if(title != NULL) {
711 window->titlelen = strlen(title);
712 } else {
713 window->titlelen = 0;
714 }
715 window->next = window->prev = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000716 /* window->owner = DISPATCHER_CURRENT();*/
717 window->owner = EK_PROC_ID(EK_CURRENT());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000718 window->active = window->inactive = window->focused = NULL;
719}
720/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000721/**
722 * Create a new window.
723 *
724 * Creates a new window. The memory for the window structure must
725 * already be allocated by the caller, and is usually done with a
726 * static declaration.
727 *
728 * This function sets up the internal structure of the ctk_window
729 * struct and creates the move and close buttons, but it does not open
730 * the window. The window must be explicitly opened by calling the
731 * ctk_window_open() function.
732 *
733 * \param window The window to be created.
734 * \param w The width of the new window.
735 * \param h The height of the new window.
736 * \param title The title of the new window.
737 */
738/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000739void
740ctk_window_new(struct ctk_window *window,
741 unsigned char w, unsigned char h,
742 char *title)
743{
744 window_new(window, w, h, title);
745
746 make_windowbuttons(window);
747}
748/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000749/**
750 * Creates a new dialog.
751 *
752 * This function only sets up the internal structure of the ctk_window
753 * struct but does not open the dialog. The dialog must be explicitly
754 * opened by calling the ctk_dialog_open() function.
755 *
756 * \param dialog The dialog to be created.
757 * \param w The width of the dialog.
758 * \param h The height of the dialog.
759 */
760/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000761void
adamdunkels35298692003-08-31 22:16:49 +0000762ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000763 unsigned char w, unsigned char h)
764{
adamdunkels35298692003-08-31 22:16:49 +0000765 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000766}
adamdunkels3af580f2003-08-11 22:27:13 +0000767/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000768/**
769 * Creates a new menu.
770 *
771 * This function sets up the internal structure of the menu, but does
772 * not add it to the menubar. Use the function ctk_menu_add() for that
773 * purpose.
774 *
775 * \param menu The menu to be created.
776 * \param title The title of the menu.
777 */
778/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000779void
adamdunkelsd07a5422003-04-05 12:22:35 +0000780ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781 char *title)
782{
783#if CTK_CONF_MENUS
784 menu->next = NULL;
785 menu->title = title;
786 menu->titlelen = strlen(title);
787 menu->active = 0;
788 menu->nitems = 0;
789#endif /* CTK_CONF_MENUS */
790}
791/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000792/**
793 * Adds a menu item to a menu.
794 *
795 * In CTK, each menu item is identified by a number which is unique
796 * within each menu. When a menu item is selected, a
797 * ctk_menuitem_activated signal is emitted and the menu item number
798 * is passed as signal data with the signal.
799 *
800 * \param menu The menu to which the menu item should be added.
801 * \param name The name of the menu item.
802 * \return The number of the menu item.
803 */
804/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000806ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000807 char *name)
808{
809#if CTK_CONF_MENUS
810 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
811 return 0;
812 }
813 menu->items[menu->nitems].title = name;
814 menu->items[menu->nitems].titlelen = strlen(name);
815 return menu->nitems++;
816#else
817 return 0;
818#endif /* CTK_CONF_MENUS */
819}
820/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000821/**
822 * \internal Adds a widget to the list of widgets that should be
823 * redrawn.
824 *
825 * \param w The widget that should be redrawn.
826 */
827/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000828static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829add_redrawwidget(struct ctk_widget *w)
830{
831 static unsigned char i;
832
833 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
834 redraw |= REDRAW_FOCUS;
835 } else {
836 redraw |= REDRAW_WIDGETS;
837 /* Check if it is in the queue already. If so, we don't add it
838 again. */
839 for(i = 0; i < redraw_widgetptr; ++i) {
840 if(redraw_widgets[i] == w) {
841 return;
842 }
843 }
844 redraw_widgets[redraw_widgetptr++] = w;
845 }
846}
847/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000848/**
849 * \internal Checks if a widget redrawn and adds it to the list of
850 * widgets to be redrawn.
851 *
852 * A widget can be redrawn only if the current CTK mode is
853 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
854 * foremost window.
855 *
856 * \param widget The widget that should be redrawn.
857 */
858/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000859static void
860widget_redraw(struct ctk_widget *widget)
861{
862 struct ctk_window *window;
863
864 if(mode != CTK_MODE_NORMAL || widget == NULL) {
865 return;
866 }
867
868 /* Only redraw widgets that are in the foremost window. If we would
869 allow redrawing widgets in non-focused windows, we would have to
870 redraw all the windows that cover the non-focused window as well,
871 which would lead to flickering.
872
873 Also, we avoid drawing any widgets when the menus are active.
874 */
875
876#if CTK_CONF_MENUS
877 if(menus.open == NULL)
878#endif /* CTK_CONF_MENUS */
879 {
880 window = widget->window;
881 if(window == dialog) {
882 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
883 } else if(dialog == NULL &&
884 (window == windows ||
885 window == &desktop_window)) {
886 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
887 }
888 }
889}
890/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000891/**
892 * Redraws a widget.
893 *
894 * This function will set a flag which causes the widget to be redrawn
895 * next time the CTK process is scheduled.
896 *
897 * \param widget The widget that is to be redrawn.
898 *
899 * \note This function should usually not be called directly since it
900 * requires typecasting of the widget parameter. The wrapper macro
901 * CTK_WIDGET_REDRAW() does the required typecast and should be used
902 * instead.
903 */
904/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000905void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000906ctk_widget_redraw(struct ctk_widget *widget)
907{
adamdunkels9f667f22003-04-16 18:29:19 +0000908 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000909 return;
910 }
911
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000912 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000913 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000914 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000915}
916/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000917/**
918 * Adds a widget to a window.
919 *
920 * This function adds a widget to a window. The order of which the
921 * widgets are added is important, as it sets the order to which
922 * widgets are cycled with the widget selection keys.
923 *
924 * \param window The window to which the widhet should be added.
925 * \param widget The widget to be added.
926 */
927/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000928void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000929ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
930 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000931{
932 if(widget->type == CTK_WIDGET_LABEL ||
933 widget->type == CTK_WIDGET_SEPARATOR) {
934 widget->next = window->inactive;
935 window->inactive = widget;
936 widget->window = window;
937 } else {
938 widget->next = window->active;
939 window->active = widget;
940 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000941 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000942 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000943 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000944 }
945}
946/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000947/**
948 * Gets the width of the desktop.
949 *
950 * \param d The desktop.
951 * \return The width of the desktop, in characters.
952 *
953 * \note The d parameter is currently unused and must be set to NULL.
954 */
955/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000956unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000957ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000958{
959 return ctk_draw_width();
960}
961/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000962/**
963 * Gets the height of the desktop.
964 *
965 * \param d The desktop.
966 * \return The height of the desktop, in characters.
967 *
968 * \note The d parameter is currently unused and must be set to NULL.
969 */
970/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000971unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000972ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000973{
974 return ctk_draw_height();
975}
976/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000977/**
978 * \internal Selects a widget in the window of the widget.
979 *
980 * \param focus The widget to be focused.
981 */
982/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000983static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000984select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000985{
986 struct ctk_window *window;
987
988 window = focus->window;
989
990 if(focus != window->focused) {
991 window->focused = focus;
992 /* The operation changed the focus, so we emit a "hover" signal
993 for those widgets that support it. */
994
995 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +0000996 ek_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +0000997 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
adamdunkels3b548c82004-07-04 11:41:39 +0000998 ek_post(window->owner, ctk_signal_button_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +0000999 }
1000
1001 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +00001002
adamdunkels3b548c82004-07-04 11:41:39 +00001003 ek_post(focus->window->owner, ctk_signal_widget_select, focus);
adamdunkels58917a82003-04-18 00:18:38 +00001004
adamdunkelse0683312003-04-09 09:02:52 +00001005 }
1006
1007}
1008/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009#define UP 0
1010#define DOWN 1
1011#define LEFT 2
1012#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +00001013static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001014switch_focus_widget(unsigned char direction)
1015{
1016 register struct ctk_window *window;
1017 register struct ctk_widget *focus;
1018 struct ctk_widget *widget;
1019
1020
1021 if(dialog != NULL) {
1022 window = dialog;
1023 } else {
1024 window = windows;
1025 }
1026
1027 /* If there are no windows open, we move focus around between the
1028 icons on the root window instead. */
1029 if(window == NULL) {
1030 window = &desktop_window;
1031 }
1032
1033 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +00001034 if(focus == NULL) {
1035 focus = window->active;
1036 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001037 add_redrawwidget(focus);
1038
1039 if((direction & 1) == 0) {
1040 /* Move focus "up" */
1041 focus = focus->next;
1042 } else {
1043 /* Move focus "down" */
1044 for(widget = window->active;
1045 widget != NULL; widget = widget->next) {
1046 if(widget->next == focus) {
1047 break;
1048 }
1049 }
1050 focus = widget;
1051 if(focus == NULL) {
1052 if(window->active != NULL) {
1053 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001054 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001055 }
1056 }
1057 }
1058 if(focus == NULL) {
1059 focus = window->active;
1060 }
adamdunkelse0683312003-04-09 09:02:52 +00001061
adamdunkelsb2486562003-04-11 20:22:03 +00001062 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001063}
1064/*-----------------------------------------------------------------------------------*/
1065#if CTK_CONF_MENUS
1066static void
1067switch_open_menu(unsigned char rightleft)
1068{
1069 struct ctk_menu *menu;
1070
1071 if(rightleft == 0) {
1072 /* Move right */
1073 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1074 if(menu->next == menus.open) {
1075 break;
1076 }
1077 }
1078 lastmenu = menus.open;
1079 menus.open = menu;
1080 if(menus.open == NULL) {
1081 for(menu = menus.menus;
1082 menu->next != NULL; menu = menu->next);
1083 menus.open = menu;
1084 }
1085 } else {
1086 /* Move to left */
1087 lastmenu = menus.open;
1088 menus.open = menus.open->next;
1089 if(menus.open == NULL) {
1090 menus.open = menus.menus;
1091 }
1092 }
1093
adamdunkels66109622003-04-24 17:17:10 +00001094 menus.open->active = 0;
1095
1096 /* if(menus.open->nitems > maxnitems) {
1097 maxnitems = menus.open->nitems;
1098 }*/
1099
adamdunkels965e2922003-06-30 20:44:57 +00001100 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001101}
1102/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001103static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001104switch_menu_item(unsigned char updown)
1105{
1106 register struct ctk_menu *m;
1107
1108 m = menus.open;
1109
1110 if(updown == 0) {
1111 /* Move up */
1112 if(m->active == 0) {
1113 m->active = m->nitems - 1;
1114 } else {
1115 --m->active;
1116 if(m->items[m->active].title[0] == '-') {
1117 --m->active;
1118 }
1119 }
1120 } else {
1121 /* Move down */
1122 if(m->active >= m->nitems - 1) {
1123 m->active = 0;
1124 } else {
1125 ++m->active;
1126 if(m->items[m->active].title[0] == '-') {
1127 ++m->active;
1128 }
1129 }
1130 }
1131
1132}
1133#endif /* CTK_CONF_MENUS */
1134/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001135static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001136activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001137{
1138 static unsigned char len;
1139
1140 if(w->type == CTK_WIDGET_BUTTON) {
1141 if(w == (struct ctk_widget *)&windows->closebutton) {
1142#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001143 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001144 ctk_window_close(windows);
1145 return REDRAW_ALL;
1146#endif /* CTK_CONF_WINDOWCLOSE */
1147 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1148#if CTK_CONF_WINDOWCLOSE
1149 mode = CTK_MODE_WINDOWMOVE;
1150#endif /* CTK_CONF_WINDOWCLOSE */
1151 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001152 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001153 }
1154#if CTK_CONF_ICONS
1155 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001156 if(w->widget.icon.owner != EK_ID_NONE) {
1157 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1158 } else {
1159 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1160 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001161#endif /* CTK_CONF_ICONS */
1162 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001163 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001164 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1165 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1166 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1167 len = strlen(w->widget.textentry.text);
1168 if(w->widget.textentry.xpos > len) {
1169 w->widget.textentry.xpos = len;
1170 }
1171 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1172 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001173 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001174 }
1175 add_redrawwidget(w);
1176 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001177 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001178 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001179 }
1180 return REDRAW_NONE;
1181}
1182/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001183static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001184textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001185 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001186{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001187 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001188 static unsigned char len, txpos, typos, tlen;
1189
1190 txpos = t->xpos;
1191 typos = t->ypos;
1192 tlen = t->len;
1193
1194 cptr = &t->text[txpos + typos * tlen];
1195
1196 switch(c) {
1197 case CH_CURS_LEFT:
1198 if(txpos > 0) {
1199 --txpos;
1200 }
1201 break;
1202
1203 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001204 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001205 ++txpos;
1206 }
1207 break;
1208
1209 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001210 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001211 break;
1212
1213 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001214 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001215 if(txpos == tlen) {
1216 --txpos;
1217 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 break;
1219
1220 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001221 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1222 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001223 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001224 break;
1225
adamdunkels9795b2e2003-08-09 23:32:37 +00001226 case CTK_CONF_WIDGETDOWN_KEY:
1227 t->state = CTK_TEXTENTRY_NORMAL;
1228 switch_focus_widget(DOWN);
1229 break;
1230 case CTK_CONF_WIDGETUP_KEY:
1231 t->state = CTK_TEXTENTRY_NORMAL;
1232 switch_focus_widget(UP);
1233 break;
1234
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001235 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001236 len = tlen - txpos;
1237 if(c == CH_DEL) {
1238 if(len == 1 && *cptr != 0) {
1239 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001240 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001241 if(txpos > 0) {
1242 --txpos;
1243 strcpy(cptr - 1, cptr);
1244 }
1245 }
1246 } else {
1247 if(ctk_arch_isprint(c)) {
1248 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001249 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001250 while(cptr2 > cptr) {
1251 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001252 --cptr2;
1253 }
adamdunkelsc9619082004-06-06 06:19:25 +00001254 ++txpos;
1255 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001256 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001257 }
1258 }
1259 break;
1260 }
1261
1262 t->xpos = txpos;
1263 t->ypos = typos;
1264}
1265/*-----------------------------------------------------------------------------------*/
1266#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001267static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001268activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001269{
1270 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001271
adamdunkelsb2486562003-04-11 20:22:03 +00001272 lastmenu = menus.open;
1273 if(menus.open == &desktopmenu) {
1274 for(w = windows; w != NULL; w = w->next) {
1275 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1276 ctk_window_open(w);
1277 menus.open = NULL;
1278 return REDRAW_ALL;
1279 }
1280 }
1281 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001282 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001283 }
1284 menus.open = NULL;
1285 return REDRAW_MENUPART;
1286}
1287/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001288static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001289menus_input(ctk_arch_key_t c)
1290{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001291
1292 if(menus.open->nitems > maxnitems) {
1293 maxnitems = menus.open->nitems;
1294 }
1295
1296
1297 switch(c) {
1298 case CH_CURS_RIGHT:
1299 switch_open_menu(1);
1300
1301 return REDRAW_MENUPART;
1302
1303 case CH_CURS_DOWN:
1304 switch_menu_item(1);
1305 return REDRAW_MENUS;
1306
1307 case CH_CURS_LEFT:
1308 switch_open_menu(0);
1309 return REDRAW_MENUPART;
1310
1311 case CH_CURS_UP:
1312 switch_menu_item(0);
1313 return REDRAW_MENUS;
1314
1315 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001316 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001317
adamdunkels88ed9c42003-03-28 12:10:09 +00001318 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001319 lastmenu = menus.open;
1320 menus.open = NULL;
1321 return REDRAW_MENUPART;
1322 }
adamdunkelsb2486562003-04-11 20:22:03 +00001323
1324 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001325}
1326#endif /* CTK_CONF_MENUS */
1327/*-----------------------------------------------------------------------------------*/
1328static void
adamdunkels3b548c82004-07-04 11:41:39 +00001329handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001330{
1331 if(mode == CTK_MODE_NORMAL) {
1332 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001333 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001334#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001335 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001336#ifdef CTK_SCREENSAVER_INIT
1337 CTK_SCREENSAVER_INIT();
1338#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001339
adamdunkelscf90b0d2003-08-09 13:34:16 +00001340#endif /* CTK_CONF_SCREENSAVER */
1341 screensaver_timer = 0;
1342 }
1343 }
1344}
1345/*-----------------------------------------------------------------------------------*/
1346static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001347unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1348{
1349 if(w != NULL) {
1350 redraw |= REDRAW_WIDGETS;
1351 add_redrawwidget(w);
1352 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1353 ((struct ctk_textentry *)w)->state =
1354 CTK_TEXTENTRY_NORMAL;
1355 }
1356 w->window->focused = NULL;
1357 }
1358}
1359/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001360EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001361{
1362 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001363 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001365 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001366 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001367#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001368 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1369 mouse_clicked;
1370 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001371 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001372
adamdunkels19a787c2003-04-09 09:22:24 +00001373#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001374
1375
adamdunkels3b548c82004-07-04 11:41:39 +00001376 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001377
adamdunkels9795b2e2003-08-09 23:32:37 +00001378 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001379 timer();
1380 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001381 } */
1382 if(timer_expired(&timer)) {
1383 timer_reset(&timer);
1384 handle_timer();
1385 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001386
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001387#if CTK_CONF_MENUS
1388 if(menus.open != NULL) {
1389 maxnitems = menus.open->nitems;
1390 } else {
1391 maxnitems = 0;
1392 }
1393#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001394
1395#if CTK_CONF_MOUSE_SUPPORT
1396 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1397
1398 /* See if there is any change in the buttons. */
1399 if(ctk_mouse_button() != mouse_button) {
1400 mouse_button = ctk_mouse_button();
1401 mouse_button_changed = 1;
1402 if(mouse_button == 0) {
1403 mouse_clicked = 1;
1404 }
1405 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001406
adamdunkelsb2486562003-04-11 20:22:03 +00001407 /* Check if the mouse pointer has moved. */
1408 if(ctk_mouse_x() != mouse_x ||
1409 ctk_mouse_y() != mouse_y) {
1410 mouse_x = ctk_mouse_x();
1411 mouse_y = ctk_mouse_y();
1412 mouse_moved = 1;
1413 }
1414
1415 mxc = ctk_mouse_xtoc(mouse_x);
1416 myc = ctk_mouse_ytoc(mouse_y);
1417#endif /* CTK_CONF_MOUSE_SUPPORT */
1418
1419
adamdunkels66109622003-04-24 17:17:10 +00001420#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001421 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001422 if(ctk_arch_keyavail()
1423#if CTK_CONF_MOUSE_SUPPORT
1424 || mouse_moved || mouse_button_changed
1425#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001426 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001427 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001428 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001429 }
adamdunkels66109622003-04-24 17:17:10 +00001430 } else
1431#endif /* CTK_CONF_SCREENSAVER */
1432 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001433#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001434 /* If there is any change in the mouse conditions, find out in
1435 which window the mouse pointer currently is in order to send
1436 the correct signals, or bring a window to focus. */
1437 if(mouse_moved || mouse_button_changed) {
1438 ctk_mouse_show();
1439 screensaver_timer = 0;
1440
1441 if(myc == 0) {
1442 /* Here we should do whatever needs to be done when the mouse
1443 moves around and clicks in the menubar. */
1444 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001445 static unsigned char titlelen;
1446
adamdunkelsb2486562003-04-11 20:22:03 +00001447 /* Find out which menu that the mouse pointer is in. Start
1448 with the ->next menu after the desktop menu. We assume
1449 that the menus start one character from the left screen
1450 side and that the desktop menu is farthest to the
1451 right. */
1452 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001453 for(menu = menus.menus->next;
1454 menu != NULL; menu = menu->next) {
1455 titlelen = menu->titlelen;
1456 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001457 break;
adamdunkelse0683312003-04-09 09:02:52 +00001458 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001459 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001460 }
adamdunkelsb2486562003-04-11 20:22:03 +00001461
1462 /* Also check desktop menu. */
1463 if(mxc >= width - 7 &&
1464 mxc <= width - 1) {
1465 menu = &desktopmenu;
1466 }
1467
1468 menus.open = menu;
1469 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001470 }
adamdunkelse0683312003-04-09 09:02:52 +00001471 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001472 --myc;
1473
1474 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001475 static unsigned char nitems;
1476
adamdunkelsb2486562003-04-11 20:22:03 +00001477 /* Do whatever needs to be done when a menu is open. */
1478
adamdunkelscf90b0d2003-08-09 13:34:16 +00001479 /* First check if the mouse pointer is in the currently open
1480 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001481 if(menus.open == &desktopmenu) {
1482 menux = width - CTK_CONF_MENUWIDTH;
1483 } else {
1484 menux = 1;
1485 for(menu = menus.menus->next; menu != menus.open;
1486 menu = menu->next) {
1487 menux += menu->titlelen;
1488 }
1489 }
1490
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001491 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001492 /* Find out which of the menu items the mouse is pointing
1493 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001494 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1495 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001496 menus.open->active = myc;
1497 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001498 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001499 }
adamdunkelsb2486562003-04-11 20:22:03 +00001500 }
1501
1502 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001503 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001504 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001505 redraw |= activate_menu();
1506 } else {
1507 lastmenu = menus.open;
1508 menus.open = NULL;
1509 redraw |= REDRAW_MENUPART;
1510 }
1511 } else {
1512 redraw |= REDRAW_MENUS;
1513 }
1514 } else {
1515
adamdunkels965e2922003-06-30 20:44:57 +00001516 /* Walk through the windows from top to bottom to see in
1517 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001518 if(dialog != NULL) {
1519 window = dialog;
1520 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001521 for(window = windows; window != NULL;
1522 window = window->next) {
1523
adamdunkelsb2486562003-04-11 20:22:03 +00001524 /* Check if the mouse is within the window. */
1525 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001526 mxc <= window->x + window->w +
1527 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001528 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001529 myc <= window->y + window->h +
1530 ctk_draw_windowtitle_height +
1531 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001532 break;
1533 }
1534 }
1535 }
1536
1537
1538 /* If we didn't find any window, and there are no windows
1539 open, the mouse pointer will definately be within the
1540 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001541 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001542 window = &desktop_window;
1543 }
1544
adamdunkels965e2922003-06-30 20:44:57 +00001545 /* If the mouse pointer moves around outside of the
1546 currently focused window (or dialog), we should not have
1547 any focused widgets in the focused window so we make sure
1548 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001549 if(windows != NULL &&
1550 window != windows &&
1551 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001553 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001554 redraw |= REDRAW_WIDGETS;*/
1555 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001556 }
1557
1558 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001559 /* If the mouse was clicked outside of the current window,
1560 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001561 if(dialog == NULL &&
1562 window != &desktop_window &&
1563 window != windows &&
1564 mouse_clicked) {
1565 /* Bring window to front. */
1566 ctk_window_open(window);
1567 redraw |= REDRAW_ALL;
1568 } else {
1569
adamdunkels965e2922003-06-30 20:44:57 +00001570 /* Find out which widget currently is under the mouse
1571 pointer and give it focus, unless it already has
1572 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001573 mxc = mxc - window->x - ctk_draw_windowborder_width;
1574 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001575
adamdunkels965e2922003-06-30 20:44:57 +00001576 /* See if the mouse pointer is on a widget. If so, it
1577 should be selected and, if the button is clicked,
1578 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001579 for(widget = window->active; widget != NULL;
1580 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001581
adamdunkelsb2486562003-04-11 20:22:03 +00001582 if(mxc >= widget->x &&
1583 mxc <= widget->x + widget->w &&
1584 (myc == widget->y ||
1585 ((widget->type == CTK_WIDGET_BITMAP ||
1586 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1587 widget->type == CTK_WIDGET_ICON) &&
1588 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001589 myc <= widget->y +
1590 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001591 break;
1592 }
1593 }
1594
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001595
1596 /* if the mouse is moved in the focused window, we emit
1597 a ctk_signal_pointer_move signal to the owner of the
1598 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001599 if(mouse_moved &&
1600 (window != &desktop_window ||
1601 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001602
adamdunkels3b548c82004-07-04 11:41:39 +00001603 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001604
1605 /* If there was a focused widget that is not below the
1606 mouse pointer, we remove focus from the widget and
1607 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001608 if(window->focused != NULL &&
1609 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001610 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001611 if(CTK_WIDGET_TYPE(window->focused) ==
1612 CTK_WIDGET_TEXTENTRY) {
1613 ((struct ctk_textentry *)(window->focused))->state =
1614 CTK_TEXTENTRY_NORMAL;
1615 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001616 window->focused = NULL;*/
1617 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001618 }
1619 redraw |= REDRAW_WIDGETS;
1620 if(widget != NULL) {
1621 select_widget(widget);
1622 }
1623 }
1624
1625 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001626 ek_post(window->owner, ctk_signal_pointer_button,
1627 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001628 if(mouse_clicked && widget != NULL) {
1629 select_widget(widget);
1630 redraw |= activate(widget);
1631 }
1632 }
1633 }
1634 }
1635 }
adamdunkelsc4902862003-04-09 00:30:45 +00001636 }
1637 }
adamdunkels19a787c2003-04-09 09:22:24 +00001638#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001639
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001640 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001641
1642 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001643
1644 screensaver_timer = 0;
1645
adamdunkelsb2486562003-04-11 20:22:03 +00001646 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001647
1648 if(dialog != NULL) {
1649 window = dialog;
1650 } else if(windows != NULL) {
1651 window = windows;
1652 } else {
1653 window = &desktop_window;
1654 }
1655 widget = window->focused;
1656
1657
1658 if(widget != NULL &&
1659 widget->type == CTK_WIDGET_TEXTENTRY &&
1660 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1661 textentry_input(c, (struct ctk_textentry *)widget);
1662 add_redrawwidget(widget);
1663#if CTK_CONF_MENUS
1664 } else if(menus.open != NULL) {
1665 redraw |= menus_input(c);
1666#endif /* CTK_CONF_MENUS */
1667 } else {
1668 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001669 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001670 switch_focus_widget(DOWN);
1671 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001672 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001673 switch_focus_widget(UP);
1674 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001675#if CTK_CONF_MENUS
1676 case CTK_CONF_MENU_KEY:
1677 if(dialog == NULL) {
1678 if(lastmenu == NULL) {
1679 menus.open = menus.menus;
1680 } else {
1681 menus.open = lastmenu;
1682 }
1683 menus.open->active = 0;
1684 redraw |= REDRAW_MENUS;
1685 }
1686 break;
1687#endif /* CTK_CONF_MENUS */
1688 case CTK_CONF_WINDOWSWITCH_KEY:
1689 if(windows != NULL) {
1690 for(window = windows; window->next != NULL;
1691 window = window->next);
1692 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001693 }
1694 break;
1695 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001696 if(c == CH_ENTER &&
1697 widget != NULL) {
1698 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001699 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001700 if(widget != NULL &&
1701 widget->type == CTK_WIDGET_TEXTENTRY) {
1702 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1703 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001704 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001705 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001706 /* window->focused = NULL;*/
1707 unfocus_widget(window->focused);
adamdunkels3b548c82004-07-04 11:41:39 +00001708 ek_post_synch(window->owner, ctk_signal_keypress, (void *)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001709 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001710 }
1711 break;
1712 }
1713 }
1714
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001715#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001716 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001717 widgetptr = redraw_widgets;
1718 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001719 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001720 *widgetptr = NULL;
1721 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001722 }
1723 redraw &= ~REDRAW_WIDGETS;
1724 redraw_widgetptr = 0;
1725 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001726#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001727 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001728#if CTK_CONF_WINDOWMOVE
1729 } else if(mode == CTK_MODE_WINDOWMOVE) {
1730
1731 redraw = 0;
1732
1733 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001734
1735#if CTK_CONF_MOUSE_SUPPORT
1736
1737 /* If the mouse has moved, we move the window as well. */
1738 if(mouse_moved) {
1739
1740 if(window->w + mxc + 2 >= width) {
1741 window->x = width - 2 - window->w;
1742 } else {
1743 window->x = mxc;
1744 }
1745
adamdunkels3b548c82004-07-04 11:41:39 +00001746 if(window->h + myc + ctk_draw_windowtitle_height +
1747 ctk_draw_windowborder_height >= height) {
1748 window->y = height - window->h -
1749 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001750 } else {
1751 window->y = myc;
1752 }
1753 if(window->y > 0) {
1754 --window->y;
1755 }
1756
1757 redraw = REDRAW_ALL;
1758 }
1759
1760 /* Check if the mouse has been clicked, and stop moving the window
1761 if so. */
1762 if(mouse_button_changed &&
1763 mouse_button == 0) {
1764 mode = CTK_MODE_NORMAL;
1765 redraw = REDRAW_ALL;
1766 }
1767#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001768
1769 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1770
1771 screensaver_timer = 0;
1772
1773 c = ctk_arch_getkey();
1774
1775 switch(c) {
1776 case CH_CURS_RIGHT:
1777 ++window->x;
1778 if(window->x + window->w + 1 >= width) {
1779 --window->x;
1780 }
1781 redraw = REDRAW_ALL;
1782 break;
1783 case CH_CURS_LEFT:
1784 if(window->x > 0) {
1785 --window->x;
1786 }
1787 redraw = REDRAW_ALL;
1788 break;
1789 case CH_CURS_DOWN:
1790 ++window->y;
1791 if(window->y + window->h + 2 >= height) {
1792 --window->y;
1793 }
1794 redraw = REDRAW_ALL;
1795 break;
1796 case CH_CURS_UP:
1797 if(window->y > 0) {
1798 --window->y;
1799 }
1800 redraw = REDRAW_ALL;
1801 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001802 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001803 mode = CTK_MODE_NORMAL;
1804 redraw = REDRAW_ALL;
1805 break;
1806 }
1807 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001808#endif /* CTK_CONF_WINDOWMOVE */
1809 }
adamdunkelsb2486562003-04-11 20:22:03 +00001810
1811 if(redraw & REDRAW_ALL) {
1812 do_redraw_all(1, height);
1813#if CTK_CONF_MENUS
1814 } else if(redraw & REDRAW_MENUPART) {
1815 do_redraw_all(1, maxnitems + 1);
1816 } else if(redraw & REDRAW_MENUS) {
1817 ctk_draw_menus(&menus);
1818#endif /* CTK_CONF_MENUS */
1819 } else if(redraw & REDRAW_FOCUS) {
1820 if(dialog != NULL) {
1821 ctk_window_redraw(dialog);
1822 } else if(windows != NULL) {
1823 ctk_window_redraw(windows);
1824 } else {
1825 ctk_window_redraw(&desktop_window);
1826 }
1827 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001828 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001829 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001830 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001831 *widgetptr = NULL;
1832 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001833 }
1834 }
1835 redraw = 0;
1836 redraw_widgetptr = 0;
1837
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001838}
1839/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001840EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1841{
1842
1843}
1844/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001845/** @} */
1846/** @} */
1847