blob: de7d64a2814d97a9a8ff02872f0de77d6654db70 [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 *
adamdunkels54d32c72004-09-01 18:14:37 +000046 * $Id: ctk.c,v 1.41 2004/09/01 18:14:37 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)
adamdunkels125483e2004-08-09 20:29:35 +000095#define ICONY_START (height - 7)
adamdunkels591724c2003-08-01 00:07:19 +000096#define ICONX_DELTA -16
adamdunkels125483e2004-08-09 20:29:35 +000097#define ICONY_DELTA -5
98#define ICONY_MAX height
99#define ICONY_MIN 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000100
adamdunkels3b548c82004-07-04 11:41:39 +0000101#ifndef ctk_arch_isprint
102unsigned char ctk_arch_isprint(char c);
103#endif /* ctk_arch_isprint */
104
105EK_POLLHANDLER(ctk_poll);
106EK_EVENTHANDLER(ctk_eventhandler, ev, data);
107EK_PROCESS(p, "CTK Contiki GUI", EK_PRIO_NORMAL, ctk_eventhandler,
108 ctk_poll, NULL);
109/*static struct ek_proc p =
110 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000111static ek_id_t ctkid;
112
adamdunkelse937ded2003-10-01 07:53:57 +0000113/** @} */
114
115/**
116 * \addtogroup signals System signals
117 * @{
118 */
adamdunkels3b548c82004-07-04 11:41:39 +0000119ek_event_t
adamdunkels35298692003-08-31 22:16:49 +0000120
adamdunkelse937ded2003-10-01 07:53:57 +0000121 /**
122 * Emitted for every key being pressed.
123 *
124 * The key is passed as signal data.*/
adamdunkels35298692003-08-31 22:16:49 +0000125 ctk_signal_keypress,
126
127 /** Emitted when a widget is activated (pressed). A pointer to the
128 widget is passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000129 ctk_signal_widget_activate,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000130
adamdunkelse937ded2003-10-01 07:53:57 +0000131 /** Same as ctk_signal_widget_activate. */
adamdunkels35298692003-08-31 22:16:49 +0000132 ctk_signal_button_activate,
133
134 /** Emitted when a widget is selected. A pointer to the widget is
135 passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000136 ctk_signal_widget_select,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000137
adamdunkelse937ded2003-10-01 07:53:57 +0000138 /** Same as ctk_signal_widget_select. */
adamdunkels35298692003-08-31 22:16:49 +0000139 ctk_signal_button_hover,
140
141 /** Emitted when a hyperlink is activated. The signal is broadcast
142 to all listeners. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000143 ctk_signal_hyperlink_activate,
adamdunkels35298692003-08-31 22:16:49 +0000144
adamdunkelse937ded2003-10-01 07:53:57 +0000145 /** Same as ctk_signal_widget_select. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000146 ctk_signal_hyperlink_hover,
adamdunkels35298692003-08-31 22:16:49 +0000147
148 /** Emitted when a menu item is activated. The number of the menu
149 item is passed as signal data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000150 ctk_signal_menu_activate,
adamdunkels35298692003-08-31 22:16:49 +0000151
152 /** Emitted when a window is closed. A pointer to the window is
153 passed as signal data. */
adamdunkelsc4902862003-04-09 00:30:45 +0000154 ctk_signal_window_close,
adamdunkels35298692003-08-31 22:16:49 +0000155
156 /** Emitted when the mouse pointer is moved. A NULL pointer is
157 passed as signal data and it is up to the listening process to
158 check the position of the mouse using the CTK mouse API.*/
adamdunkelsc4902862003-04-09 00:30:45 +0000159 ctk_signal_pointer_move,
adamdunkels35298692003-08-31 22:16:49 +0000160
161 /** Emitted when a mouse button is pressed. The button is passed as
162 signal data to the listening process. */
adamdunkelsb2486562003-04-11 20:22:03 +0000163 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000164
adamdunkels66109622003-04-24 17:17:10 +0000165#if CTK_CONF_SCREENSAVER
adamdunkelse937ded2003-10-01 07:53:57 +0000166/** Emitted when the user has been idle long enough for the
167 screensaver to start. */
adamdunkels3b548c82004-07-04 11:41:39 +0000168ek_event_t ctk_signal_screensaver_stop,
adamdunkelse937ded2003-10-01 07:53:57 +0000169 /** Emitted when the user presses a key or moves the mouse when the
170 screensaver is active. */
adamdunkels9795b2e2003-08-09 23:32:37 +0000171 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000172#endif /* CTK_CONF_SCREENSAVER */
173
adamdunkelse937ded2003-10-01 07:53:57 +0000174/** @} */
175
176/**
177 * \addtogroup ctk
178 * @{
179 */
adamdunkels66109622003-04-24 17:17:10 +0000180
adamdunkels19a787c2003-04-09 09:22:24 +0000181#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000182unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000183#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000184
adamdunkels9795b2e2003-08-09 23:32:37 +0000185static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000186unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels3b548c82004-07-04 11:41:39 +0000187/*static ek_clock_t start, current;*/
188static struct timer timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000189
190#if CTK_CONF_MENUS
191/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000192/**
193 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000194 *
195 * Creates the leftmost menu, "Desktop". Since the desktop menu
196 * contains the list of all open windows, this function will be called
197 * whenever a window is opened or closed.
198 */
adamdunkels35298692003-08-31 22:16:49 +0000199/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000200static void
201make_desktopmenu(void)
202{
203 struct ctk_window *w;
204
205 desktopmenu.nitems = 0;
206
207 if(windows == NULL) {
208 ctk_menuitem_add(&desktopmenu, "(No windows)");
209 } else {
210 for(w = windows; w != NULL; w = w->next) {
211 ctk_menuitem_add(&desktopmenu, w->title);
212 }
213 }
214}
215#endif /* CTK_CONF_MENUS */
216/*-----------------------------------------------------------------------------------*/
adamdunkels125483e2004-08-09 20:29:35 +0000217static void
218arrange_icons(void)
219{
220 struct ctk_widget *icon;
221
222 iconx = ICONX_START;
223 icony = ICONY_START;
224
225 for(icon = desktop_window.active; icon != NULL; icon = icon->next) {
226
227 icon->x = iconx;
228 icon->y = icony;
229
230 icony += ICONY_DELTA;
231 if(icony >= ICONY_MAX ||
232 icony < ICONY_MIN) {
233 icony = ICONY_START;
234 iconx += ICONX_DELTA;
235 }
236 }
237}
238/*-----------------------------------------------------------------------------------*/
239void
240ctk_restore(void)
241{
242 ctk_draw_init();
243
244 height = ctk_draw_height();
245 width = ctk_draw_width();
246
247 arrange_icons();
248
249 redraw = REDRAW_ALL;
250}
251/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000252/**
253 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000254 *
adamdunkels35298692003-08-31 22:16:49 +0000255 * This function must be called before any other CTK function, but
256 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000257 */
adamdunkels35298692003-08-31 22:16:49 +0000258/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000259void
260ctk_init(void)
261{
adamdunkels3b548c82004-07-04 11:41:39 +0000262 ctkid = ek_start(&p);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263
264 windows = NULL;
265 dialog = NULL;
266
267#if CTK_CONF_MENUS
268 ctk_menu_new(&desktopmenu, "Desktop");
269 make_desktopmenu();
270 menus.menus = menus.desktopmenu = &desktopmenu;
271#endif /* CTK_CONF_MENUS */
272
adamdunkelsb2486562003-04-11 20:22:03 +0000273#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000274 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000275 ctk_mouse_show();
276#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000277
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000278 ctk_draw_init();
279
280 height = ctk_draw_height();
281 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000282
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000283 desktop_window.active = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000284 desktop_window.owner = ctkid;
adamdunkelsb2486562003-04-11 20:22:03 +0000285
adamdunkels3b548c82004-07-04 11:41:39 +0000286 ctk_signal_keypress = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000287
288 ctk_signal_button_activate =
adamdunkels3b548c82004-07-04 11:41:39 +0000289 ctk_signal_widget_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000290
291 ctk_signal_button_hover =
292 ctk_signal_hyperlink_hover =
adamdunkels3b548c82004-07-04 11:41:39 +0000293 ctk_signal_widget_select = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000294
adamdunkels3b548c82004-07-04 11:41:39 +0000295 ctk_signal_hyperlink_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000296
adamdunkels3b548c82004-07-04 11:41:39 +0000297 ctk_signal_menu_activate = ek_alloc_event();
298 ctk_signal_window_close = ek_alloc_event();
adamdunkelsc4902862003-04-09 00:30:45 +0000299
adamdunkels3b548c82004-07-04 11:41:39 +0000300 ctk_signal_pointer_move = ek_alloc_event();
301 ctk_signal_pointer_button = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000302
303
304#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +0000305 ctk_signal_screensaver_start = ek_alloc_event();
306 ctk_signal_screensaver_stop = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000307#endif /* CTK_CONF_SCREENSAVER */
308
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000309
310 mode = CTK_MODE_NORMAL;
311
312 iconx = ICONX_START;
313 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000314
315 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000316
adamdunkels3b548c82004-07-04 11:41:39 +0000317 /* start = ek_clock();*/
318 timer_set(&timer, CLOCK_SECOND);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000319}
adamdunkelse937ded2003-10-01 07:53:57 +0000320
321/**
322 * \addtogroup ctkappfunc
323 * @{
324 */
325
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000326/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000327/**
328 * Sets the current CTK mode.
329 *
330 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
331 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
332 * keypresses and mouse pointer movements are processed and the screen
333 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
334 * performed and the first key press or pointer movement will cause
335 * the ctk_signal_screensaver_stop to be emitted. In the
336 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
337 * ignored and no screen redraws are made.
338 *
339 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000340 */
adamdunkels35298692003-08-31 22:16:49 +0000341/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000342void
343ctk_mode_set(unsigned char m) {
344 mode = m;
345}
346/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000347/**
348 * Retrieves the current CTK mode.
349 *
350 * \return The current CTK mode.
351 */
352/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000353unsigned char
354ctk_mode_get(void) {
355 return mode;
356}
357/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000358/**
359 * Add an icon to the desktop.
360 *
361 * \param icon The icon to be added.
adamdunkels0404ef12003-09-04 19:36:04 +0000362 *
363 * \param id The process ID of the process that owns the icon.
adamdunkels35298692003-08-31 22:16:49 +0000364 */
365/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000366void
adamdunkels0404ef12003-09-04 19:36:04 +0000367ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, ek_id_t id)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000368{
adamdunkels0404ef12003-09-04 19:36:04 +0000369#if CTK_CONF_ICONS
adamdunkels125483e2004-08-09 20:29:35 +0000370 /* icon->x = iconx;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000371 icon->y = icony;
adamdunkels0404ef12003-09-04 19:36:04 +0000372 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000373
374 icony += ICONY_DELTA;
375 if(icony >= ICONY_MAX) {
376 icony = ICONY_START;
377 iconx += ICONX_DELTA;
adamdunkels125483e2004-08-09 20:29:35 +0000378 }*/
379 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000380 ctk_widget_add(&desktop_window, icon);
adamdunkels125483e2004-08-09 20:29:35 +0000381 arrange_icons();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000382#endif /* CTK_CONF_ICONS */
383}
384/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000385/**
386 * Open a dialog box.
387 *
388 * \param d The dialog to be opened.
389 */
390/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000391void
392ctk_dialog_open(struct ctk_window *d)
393{
394 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000395 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000396}
397/*-----------------------------------------------------------------------------------*/
398/**
399 * Close the dialog box, if one is open.
400 *
401 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000402/*-----------------------------------------------------------------------------------*/
403void
404ctk_dialog_close(void)
405{
406 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000407 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000408}
409/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000410/**
411 * Open a window, or bring window to front if already open.
412 *
413 * \param w The window to be opened.
414 */
415/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000416void
adamdunkelsd07a5422003-04-05 12:22:35 +0000417ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000418{
419 struct ctk_window *w2;
420
421 /* Check if already open. */
422 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
423 if(w2 == NULL) {
424 /* Not open, so we add it at the head of the list of open
425 windows. */
426 w->next = windows;
427 if(windows != NULL) {
428 windows->prev = w;
429 }
430 windows = w;
431 w->prev = NULL;
432 } else {
433 /* Window already open, so we move it to the front of the windows
434 list. */
435 if(w != windows) {
436 if(w->next != NULL) {
437 w->next->prev = w->prev;
438 }
439 if(w->prev != NULL) {
440 w->prev->next = w->next;
441 }
442 w->next = windows;
443 windows->prev = w;
444 windows = w;
445 w->prev = NULL;
446 }
447 }
448
449#if CTK_CONF_MENUS
450 /* Recreate the Desktop menu's window entries.*/
451 make_desktopmenu();
452#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000453
454 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000455}
456/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000457/**
458 * Close a window if it is open.
459 *
460 * If the window is not open, this function does nothing.
461 *
462 * \param w The window to be closed.
463 */
464/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000465void
466ctk_window_close(struct ctk_window *w)
467{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000468 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000469
470 if(w == NULL) {
471 return;
472 }
473
474 /* Check if the window to be closed is the first window on the
475 list. */
476 if(w == windows) {
477 windows = w->next;
478 if(windows != NULL) {
479 windows->prev = NULL;
480 }
481 w->next = w->prev = NULL;
482 } else {
483 /* Otherwise we step through the list until we find the window
484 before the one to be closed. We then redirect its ->next
485 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000486 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
487
488 if(w2 == NULL) {
489 /* The window wasn't open, so there is nothing more for us to
490 do. */
491 return;
492 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000493
494 if(w->next != NULL) {
495 w->next->prev = w->prev;
496 }
497 w2->next = w->next;
498
499 w->next = w->prev = NULL;
500 }
501
502#if CTK_CONF_MENUS
503 /* Recreate the Desktop menu's window entries.*/
504 make_desktopmenu();
505#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000506 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000507}
508/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000509/**
510 * \internal Create the move and close buttons on the window titlebar.
511 */
512/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000513static void
514make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000515{
adamdunkels3b548c82004-07-04 11:41:39 +0000516 unsigned char placement;
517
518 if(ctk_draw_windowtitle_height >= 2) {
519 placement = -1 - ctk_draw_windowtitle_height/2;
520 } else {
521 placement = -1;
522 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000523#if CTK_CONF_WINDOWMOVE
adamdunkels3b548c82004-07-04 11:41:39 +0000524 CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
525 window->titlelen, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526#else
adamdunkels3b548c82004-07-04 11:41:39 +0000527 CTK_LABEL_NEW(&window->titlebutton, 0, placement,
528 window->titlelen, 1, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529#endif /* CTK_CONF_WINDOWMOVE */
530 CTK_WIDGET_ADD(window, &window->titlebutton);
531
532
533#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +0000534 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, placement,
535 1, "x");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000536#else
adamdunkels3b548c82004-07-04 11:41:39 +0000537 CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
538 3, 1, " ");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000539#endif /* CTK_CONF_WINDOWCLOSE */
540 CTK_WIDGET_ADD(window, &window->closebutton);
541}
542/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000543/**
544 * Remove all widgets from a window.
545 *
546 * \param w The window to be cleared.
547 */
548/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000549void
adamdunkels35298692003-08-31 22:16:49 +0000550ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000551{
adamdunkels35298692003-08-31 22:16:49 +0000552 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000553
adamdunkels35298692003-08-31 22:16:49 +0000554 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000555}
556/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000557/**
558 * Add a menu to the menu bar.
559 *
560 * \param menu The menu to be added.
561 *
562 * \note Do not call this function multiple times for the same menu,
563 * as no check is made to see if the menu already is in the menu bar.
564 */
565/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000566void
567ctk_menu_add(struct ctk_menu *menu)
568{
569#if CTK_CONF_MENUS
570 struct ctk_menu *m;
571
572 if(lastmenu == NULL) {
573 lastmenu = menu;
574 }
575
576 for(m = menus.menus; m->next != NULL; m = m->next) {
577 if(m == menu) {
578 return;
579 }
580 }
581 m->next = menu;
582 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000583
584 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000585#endif /* CTK_CONF_MENUS */
586}
587/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000588/**
589 * Remove a menu from the menu bar.
590 *
591 * \param menu The menu to be removed.
592 */
593/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000594void
595ctk_menu_remove(struct ctk_menu *menu)
596{
597#if CTK_CONF_MENUS
598 struct ctk_menu *m;
599
600 for(m = menus.menus; m->next != NULL; m = m->next) {
601 if(m->next == menu) {
602 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000603 if(menu == lastmenu) {
604 lastmenu = NULL;
605 }
606 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000607 return;
608 }
609 }
610#endif /* CTK_CONF_MENUS */
611}
612/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000613/**
614 * \internal Redraws everything on the screen within the clip
615 * interval.
616 *
617 * \param clipy1 The upper bound of the clip interval
618 * \param clipy2 The lower bound of the clip interval
619 */
620/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000621static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000622do_redraw_all(unsigned char clipy1, unsigned char clipy2)
623{
624 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000625 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000626
627 if(mode != CTK_MODE_NORMAL &&
628 mode != CTK_MODE_WINDOWMOVE) {
629 return;
630 }
631
632 ctk_draw_clear(clipy1, clipy2);
633
634 /* Draw widgets in root window */
635 for(widget = desktop_window.active;
636 widget != NULL; widget = widget->next) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000637 ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000638 }
639
640 /* Draw windows */
641 if(windows != NULL) {
642 /* Find the last window.*/
643 for(w = windows; w->next != NULL; w = w->next);
644
645 /* Draw the windows from back to front. */
646 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000647 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000648 ctk_draw_window(w, 0, clipy1, clipy2);
649 }
650 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000651 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000652 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
653 }
654
655 /* Draw dialog (if any) */
656 if(dialog != NULL) {
657 ctk_draw_dialog(dialog);
658 }
659
660#if CTK_CONF_MENUS
661 ctk_draw_menus(&menus);
662#endif /* CTK_CONF_MENUS */
663}
664/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000665/**
666 * Redraw the entire desktop.
667 *
668 * \param d The desktop to be redrawn.
669 *
670 * \note Currently the parameter d is not used, but must be set to
671 * NULL.
adamdunkelse937ded2003-10-01 07:53:57 +0000672 *
adamdunkels35298692003-08-31 22:16:49 +0000673 */
674/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000675void
adamdunkels965e2922003-06-30 20:44:57 +0000676ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000677{
adamdunkels3b548c82004-07-04 11:41:39 +0000678 if(EK_CURRENT() == &p) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000679 if(mode == CTK_MODE_NORMAL ||
680 mode == CTK_MODE_WINDOWMOVE) {
681 do_redraw_all(1, height);
682 }
683 } else {
684 redraw |= REDRAW_ALL;
685 }
686}
687/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000688/**
689 * Redraw a window.
690 *
691 * This function redraws the window, but only if it is the foremost
692 * one on the desktop.
693 *
694 * \param w The window to be redrawn.
695 */
696/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000697void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000698ctk_window_redraw(struct ctk_window *w)
699{
700 /* Only redraw the window if it is a dialog or if it is the foremost
701 window. */
702 if(mode != CTK_MODE_NORMAL) {
703 return;
704 }
705
706 if(w == dialog) {
707 ctk_draw_dialog(w);
708 } else if(dialog == NULL &&
709#if CTK_CONF_MENUS
710 menus.open == NULL &&
711#endif /* CTK_CONF_MENUS */
712 windows == w) {
713 ctk_draw_window(w, CTK_FOCUS_WINDOW,
714 0, height);
715 }
716}
717/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000718/**
719 * \internal Creates a new window.
720 *
721 * \param window The window to be created.
722 * \param w The width of the window.
723 * \param h The height of the window.
724 * \param title The title of the window.
725 */
726/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000727static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000728window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000729 unsigned char w, unsigned char h,
730 char *title)
731{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000732
733 if(w >= width - 2) {
734 window->x = 0;
735 } else {
736 window->x = (width - w - 2) / 2;
737 }
738 if(h >= height - 3) {
739 window->y = 0;
740 } else {
adamdunkels3b548c82004-07-04 11:41:39 +0000741 window->y = (height - h - ctk_draw_windowtitle_height) / 2;
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000742 }
743
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000744 window->w = w;
745 window->h = h;
746 window->title = title;
747 if(title != NULL) {
748 window->titlelen = strlen(title);
749 } else {
750 window->titlelen = 0;
751 }
752 window->next = window->prev = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000753 /* window->owner = DISPATCHER_CURRENT();*/
754 window->owner = EK_PROC_ID(EK_CURRENT());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000755 window->active = window->inactive = window->focused = NULL;
756}
757/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000758/**
759 * Create a new window.
760 *
761 * Creates a new window. The memory for the window structure must
762 * already be allocated by the caller, and is usually done with a
763 * static declaration.
764 *
765 * This function sets up the internal structure of the ctk_window
766 * struct and creates the move and close buttons, but it does not open
767 * the window. The window must be explicitly opened by calling the
768 * ctk_window_open() function.
769 *
770 * \param window The window to be created.
771 * \param w The width of the new window.
772 * \param h The height of the new window.
773 * \param title The title of the new window.
774 */
775/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000776void
777ctk_window_new(struct ctk_window *window,
778 unsigned char w, unsigned char h,
779 char *title)
780{
781 window_new(window, w, h, title);
782
783 make_windowbuttons(window);
784}
785/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000786/**
787 * Creates a new dialog.
788 *
789 * This function only sets up the internal structure of the ctk_window
790 * struct but does not open the dialog. The dialog must be explicitly
791 * opened by calling the ctk_dialog_open() function.
792 *
793 * \param dialog The dialog to be created.
794 * \param w The width of the dialog.
795 * \param h The height of the dialog.
796 */
797/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000798void
adamdunkels35298692003-08-31 22:16:49 +0000799ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000800 unsigned char w, unsigned char h)
801{
adamdunkels35298692003-08-31 22:16:49 +0000802 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000803}
adamdunkels3af580f2003-08-11 22:27:13 +0000804/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000805/**
806 * Creates a new menu.
807 *
808 * This function sets up the internal structure of the menu, but does
809 * not add it to the menubar. Use the function ctk_menu_add() for that
810 * purpose.
811 *
812 * \param menu The menu to be created.
813 * \param title The title of the menu.
814 */
815/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000816void
adamdunkelsd07a5422003-04-05 12:22:35 +0000817ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000818 char *title)
819{
820#if CTK_CONF_MENUS
821 menu->next = NULL;
822 menu->title = title;
823 menu->titlelen = strlen(title);
824 menu->active = 0;
825 menu->nitems = 0;
826#endif /* CTK_CONF_MENUS */
827}
828/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000829/**
830 * Adds a menu item to a menu.
831 *
832 * In CTK, each menu item is identified by a number which is unique
833 * within each menu. When a menu item is selected, a
834 * ctk_menuitem_activated signal is emitted and the menu item number
835 * is passed as signal data with the signal.
836 *
837 * \param menu The menu to which the menu item should be added.
838 * \param name The name of the menu item.
839 * \return The number of the menu item.
840 */
841/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000842unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000843ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000844 char *name)
845{
846#if CTK_CONF_MENUS
847 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
848 return 0;
849 }
850 menu->items[menu->nitems].title = name;
851 menu->items[menu->nitems].titlelen = strlen(name);
852 return menu->nitems++;
853#else
854 return 0;
855#endif /* CTK_CONF_MENUS */
856}
857/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000858/**
859 * \internal Adds a widget to the list of widgets that should be
860 * redrawn.
861 *
862 * \param w The widget that should be redrawn.
863 */
864/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000865static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000866add_redrawwidget(struct ctk_widget *w)
867{
868 static unsigned char i;
869
870 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
871 redraw |= REDRAW_FOCUS;
872 } else {
873 redraw |= REDRAW_WIDGETS;
874 /* Check if it is in the queue already. If so, we don't add it
875 again. */
876 for(i = 0; i < redraw_widgetptr; ++i) {
877 if(redraw_widgets[i] == w) {
878 return;
879 }
880 }
881 redraw_widgets[redraw_widgetptr++] = w;
882 }
883}
884/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000885/**
886 * \internal Checks if a widget redrawn and adds it to the list of
887 * widgets to be redrawn.
888 *
889 * A widget can be redrawn only if the current CTK mode is
890 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
891 * foremost window.
892 *
893 * \param widget The widget that should be redrawn.
894 */
895/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000896static void
897widget_redraw(struct ctk_widget *widget)
898{
899 struct ctk_window *window;
900
901 if(mode != CTK_MODE_NORMAL || widget == NULL) {
902 return;
903 }
904
905 /* Only redraw widgets that are in the foremost window. If we would
906 allow redrawing widgets in non-focused windows, we would have to
907 redraw all the windows that cover the non-focused window as well,
908 which would lead to flickering.
909
910 Also, we avoid drawing any widgets when the menus are active.
911 */
912
913#if CTK_CONF_MENUS
914 if(menus.open == NULL)
915#endif /* CTK_CONF_MENUS */
916 {
917 window = widget->window;
918 if(window == dialog) {
919 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
920 } else if(dialog == NULL &&
921 (window == windows ||
922 window == &desktop_window)) {
923 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
924 }
925 }
926}
927/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000928/**
929 * Redraws a widget.
930 *
931 * This function will set a flag which causes the widget to be redrawn
932 * next time the CTK process is scheduled.
933 *
934 * \param widget The widget that is to be redrawn.
935 *
936 * \note This function should usually not be called directly since it
937 * requires typecasting of the widget parameter. The wrapper macro
938 * CTK_WIDGET_REDRAW() does the required typecast and should be used
939 * instead.
940 */
941/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000942void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000943ctk_widget_redraw(struct ctk_widget *widget)
944{
adamdunkels9f667f22003-04-16 18:29:19 +0000945 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000946 return;
947 }
948
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000949 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000950 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000951 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000952}
953/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000954/**
955 * Adds a widget to a window.
956 *
957 * This function adds a widget to a window. The order of which the
958 * widgets are added is important, as it sets the order to which
959 * widgets are cycled with the widget selection keys.
960 *
961 * \param window The window to which the widhet should be added.
962 * \param widget The widget to be added.
963 */
964/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000965void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000966ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
967 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000968{
969 if(widget->type == CTK_WIDGET_LABEL ||
970 widget->type == CTK_WIDGET_SEPARATOR) {
971 widget->next = window->inactive;
972 window->inactive = widget;
973 widget->window = window;
974 } else {
975 widget->next = window->active;
976 window->active = widget;
977 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000978 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000979 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000980 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000981 }
982}
983/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000984/**
985 * Gets the width of the desktop.
986 *
987 * \param d The desktop.
988 * \return The width of the desktop, in characters.
989 *
990 * \note The d parameter is currently unused and must be set to NULL.
991 */
992/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000993unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000994ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000995{
996 return ctk_draw_width();
997}
998/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000999/**
1000 * Gets the height of the desktop.
1001 *
1002 * \param d The desktop.
1003 * \return The height of the desktop, in characters.
1004 *
1005 * \note The d parameter is currently unused and must be set to NULL.
1006 */
1007/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001008unsigned char
adamdunkels35298692003-08-31 22:16:49 +00001009ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001010{
1011 return ctk_draw_height();
1012}
1013/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +00001014/**
1015 * \internal Selects a widget in the window of the widget.
1016 *
1017 * \param focus The widget to be focused.
1018 */
1019/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001020static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +00001021select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +00001022{
1023 struct ctk_window *window;
1024
1025 window = focus->window;
1026
1027 if(focus != window->focused) {
1028 window->focused = focus;
1029 /* The operation changed the focus, so we emit a "hover" signal
1030 for those widgets that support it. */
1031
1032 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001033 ek_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001034 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001035 ek_post(window->owner, ctk_signal_button_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001036 }
1037
1038 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +00001039
adamdunkels3b548c82004-07-04 11:41:39 +00001040 ek_post(focus->window->owner, ctk_signal_widget_select, focus);
adamdunkels58917a82003-04-18 00:18:38 +00001041
adamdunkelse0683312003-04-09 09:02:52 +00001042 }
1043
1044}
1045/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001046#define UP 0
1047#define DOWN 1
1048#define LEFT 2
1049#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +00001050static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001051switch_focus_widget(unsigned char direction)
1052{
1053 register struct ctk_window *window;
1054 register struct ctk_widget *focus;
1055 struct ctk_widget *widget;
1056
1057
1058 if(dialog != NULL) {
1059 window = dialog;
1060 } else {
1061 window = windows;
1062 }
1063
1064 /* If there are no windows open, we move focus around between the
1065 icons on the root window instead. */
1066 if(window == NULL) {
1067 window = &desktop_window;
1068 }
1069
1070 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +00001071 if(focus == NULL) {
1072 focus = window->active;
1073 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001074 add_redrawwidget(focus);
1075
1076 if((direction & 1) == 0) {
1077 /* Move focus "up" */
1078 focus = focus->next;
1079 } else {
1080 /* Move focus "down" */
1081 for(widget = window->active;
1082 widget != NULL; widget = widget->next) {
1083 if(widget->next == focus) {
1084 break;
1085 }
1086 }
1087 focus = widget;
1088 if(focus == NULL) {
1089 if(window->active != NULL) {
1090 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001091 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001092 }
1093 }
1094 }
1095 if(focus == NULL) {
1096 focus = window->active;
1097 }
adamdunkelse0683312003-04-09 09:02:52 +00001098
adamdunkelsb2486562003-04-11 20:22:03 +00001099 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001100}
1101/*-----------------------------------------------------------------------------------*/
1102#if CTK_CONF_MENUS
1103static void
1104switch_open_menu(unsigned char rightleft)
1105{
1106 struct ctk_menu *menu;
1107
1108 if(rightleft == 0) {
1109 /* Move right */
1110 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1111 if(menu->next == menus.open) {
1112 break;
1113 }
1114 }
1115 lastmenu = menus.open;
1116 menus.open = menu;
1117 if(menus.open == NULL) {
1118 for(menu = menus.menus;
1119 menu->next != NULL; menu = menu->next);
1120 menus.open = menu;
1121 }
1122 } else {
1123 /* Move to left */
1124 lastmenu = menus.open;
1125 menus.open = menus.open->next;
1126 if(menus.open == NULL) {
1127 menus.open = menus.menus;
1128 }
1129 }
1130
adamdunkels66109622003-04-24 17:17:10 +00001131 menus.open->active = 0;
1132
1133 /* if(menus.open->nitems > maxnitems) {
1134 maxnitems = menus.open->nitems;
1135 }*/
1136
adamdunkels965e2922003-06-30 20:44:57 +00001137 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001138}
1139/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001140static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001141switch_menu_item(unsigned char updown)
1142{
1143 register struct ctk_menu *m;
1144
1145 m = menus.open;
1146
1147 if(updown == 0) {
1148 /* Move up */
1149 if(m->active == 0) {
1150 m->active = m->nitems - 1;
1151 } else {
1152 --m->active;
1153 if(m->items[m->active].title[0] == '-') {
1154 --m->active;
1155 }
1156 }
1157 } else {
1158 /* Move down */
1159 if(m->active >= m->nitems - 1) {
1160 m->active = 0;
1161 } else {
1162 ++m->active;
1163 if(m->items[m->active].title[0] == '-') {
1164 ++m->active;
1165 }
1166 }
1167 }
1168
1169}
1170#endif /* CTK_CONF_MENUS */
1171/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001172static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001173activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001174{
1175 static unsigned char len;
1176
1177 if(w->type == CTK_WIDGET_BUTTON) {
1178 if(w == (struct ctk_widget *)&windows->closebutton) {
1179#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001180 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001181 ctk_window_close(windows);
1182 return REDRAW_ALL;
1183#endif /* CTK_CONF_WINDOWCLOSE */
1184 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1185#if CTK_CONF_WINDOWCLOSE
1186 mode = CTK_MODE_WINDOWMOVE;
1187#endif /* CTK_CONF_WINDOWCLOSE */
1188 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001189 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001190 }
1191#if CTK_CONF_ICONS
1192 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001193 if(w->widget.icon.owner != EK_ID_NONE) {
1194 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1195 } else {
1196 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1197 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001198#endif /* CTK_CONF_ICONS */
1199 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001200 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001201 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1202 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1203 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1204 len = strlen(w->widget.textentry.text);
1205 if(w->widget.textentry.xpos > len) {
1206 w->widget.textentry.xpos = len;
1207 }
1208 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1209 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001210 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001211 }
1212 add_redrawwidget(w);
1213 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001214 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001215 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001216 }
1217 return REDRAW_NONE;
1218}
1219/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001220static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001221textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001222 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001223{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001224 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001225 static unsigned char len, txpos, typos, tlen;
1226
1227 txpos = t->xpos;
1228 typos = t->ypos;
1229 tlen = t->len;
1230
1231 cptr = &t->text[txpos + typos * tlen];
1232
1233 switch(c) {
1234 case CH_CURS_LEFT:
1235 if(txpos > 0) {
1236 --txpos;
1237 }
1238 break;
1239
1240 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001241 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001242 ++txpos;
1243 }
1244 break;
1245
1246 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001247 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001248 break;
1249
1250 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001251 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001252 if(txpos == tlen) {
1253 --txpos;
1254 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001255 break;
1256
1257 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001258 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1259 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001260 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001261 break;
1262
adamdunkels9795b2e2003-08-09 23:32:37 +00001263 case CTK_CONF_WIDGETDOWN_KEY:
1264 t->state = CTK_TEXTENTRY_NORMAL;
1265 switch_focus_widget(DOWN);
1266 break;
1267 case CTK_CONF_WIDGETUP_KEY:
1268 t->state = CTK_TEXTENTRY_NORMAL;
1269 switch_focus_widget(UP);
1270 break;
1271
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001273 len = tlen - txpos;
1274 if(c == CH_DEL) {
1275 if(len == 1 && *cptr != 0) {
1276 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001277 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001278 if(txpos > 0) {
1279 --txpos;
1280 strcpy(cptr - 1, cptr);
1281 }
1282 }
1283 } else {
1284 if(ctk_arch_isprint(c)) {
1285 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001286 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001287 while(cptr2 > cptr) {
1288 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001289 --cptr2;
1290 }
adamdunkelsc9619082004-06-06 06:19:25 +00001291 ++txpos;
1292 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001293 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001294 }
1295 }
1296 break;
1297 }
1298
1299 t->xpos = txpos;
1300 t->ypos = typos;
1301}
1302/*-----------------------------------------------------------------------------------*/
1303#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001304static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001305activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001306{
1307 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001308
adamdunkelsb2486562003-04-11 20:22:03 +00001309 lastmenu = menus.open;
1310 if(menus.open == &desktopmenu) {
1311 for(w = windows; w != NULL; w = w->next) {
1312 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1313 ctk_window_open(w);
1314 menus.open = NULL;
1315 return REDRAW_ALL;
1316 }
1317 }
1318 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001319 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001320 }
1321 menus.open = NULL;
1322 return REDRAW_MENUPART;
1323}
1324/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001325static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001326menus_input(ctk_arch_key_t c)
1327{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001328
1329 if(menus.open->nitems > maxnitems) {
1330 maxnitems = menus.open->nitems;
1331 }
1332
1333
1334 switch(c) {
1335 case CH_CURS_RIGHT:
1336 switch_open_menu(1);
1337
1338 return REDRAW_MENUPART;
1339
1340 case CH_CURS_DOWN:
1341 switch_menu_item(1);
1342 return REDRAW_MENUS;
1343
1344 case CH_CURS_LEFT:
1345 switch_open_menu(0);
1346 return REDRAW_MENUPART;
1347
1348 case CH_CURS_UP:
1349 switch_menu_item(0);
1350 return REDRAW_MENUS;
1351
1352 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001353 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001354
adamdunkels88ed9c42003-03-28 12:10:09 +00001355 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001356 lastmenu = menus.open;
1357 menus.open = NULL;
1358 return REDRAW_MENUPART;
1359 }
adamdunkelsb2486562003-04-11 20:22:03 +00001360
1361 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001362}
1363#endif /* CTK_CONF_MENUS */
1364/*-----------------------------------------------------------------------------------*/
1365static void
adamdunkels3b548c82004-07-04 11:41:39 +00001366handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001367{
1368 if(mode == CTK_MODE_NORMAL) {
1369 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001370 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001371#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001372 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001373#ifdef CTK_SCREENSAVER_INIT
1374 CTK_SCREENSAVER_INIT();
1375#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001376
adamdunkelscf90b0d2003-08-09 13:34:16 +00001377#endif /* CTK_CONF_SCREENSAVER */
1378 screensaver_timer = 0;
1379 }
1380 }
1381}
1382/*-----------------------------------------------------------------------------------*/
1383static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001384unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1385{
1386 if(w != NULL) {
1387 redraw |= REDRAW_WIDGETS;
1388 add_redrawwidget(w);
1389 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1390 ((struct ctk_textentry *)w)->state =
1391 CTK_TEXTENTRY_NORMAL;
1392 }
1393 w->window->focused = NULL;
1394 }
1395}
1396/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001397EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001398{
1399 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001400 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001401 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001402 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001403 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001404#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001405 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1406 mouse_clicked;
1407 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001408 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001409
adamdunkels19a787c2003-04-09 09:22:24 +00001410#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001411
1412
adamdunkels3b548c82004-07-04 11:41:39 +00001413 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001414
adamdunkels9795b2e2003-08-09 23:32:37 +00001415 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001416 timer();
1417 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001418 } */
1419 if(timer_expired(&timer)) {
1420 timer_reset(&timer);
1421 handle_timer();
1422 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001423
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001424#if CTK_CONF_MENUS
1425 if(menus.open != NULL) {
1426 maxnitems = menus.open->nitems;
1427 } else {
1428 maxnitems = 0;
1429 }
1430#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001431
1432#if CTK_CONF_MOUSE_SUPPORT
1433 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1434
1435 /* See if there is any change in the buttons. */
1436 if(ctk_mouse_button() != mouse_button) {
1437 mouse_button = ctk_mouse_button();
1438 mouse_button_changed = 1;
1439 if(mouse_button == 0) {
1440 mouse_clicked = 1;
1441 }
1442 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001443
adamdunkelsb2486562003-04-11 20:22:03 +00001444 /* Check if the mouse pointer has moved. */
1445 if(ctk_mouse_x() != mouse_x ||
1446 ctk_mouse_y() != mouse_y) {
1447 mouse_x = ctk_mouse_x();
1448 mouse_y = ctk_mouse_y();
1449 mouse_moved = 1;
1450 }
1451
1452 mxc = ctk_mouse_xtoc(mouse_x);
1453 myc = ctk_mouse_ytoc(mouse_y);
1454#endif /* CTK_CONF_MOUSE_SUPPORT */
1455
1456
adamdunkels66109622003-04-24 17:17:10 +00001457#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001458 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001459 if(ctk_arch_keyavail()
1460#if CTK_CONF_MOUSE_SUPPORT
1461 || mouse_moved || mouse_button_changed
1462#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001463 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001464 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001465 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001466 }
adamdunkels66109622003-04-24 17:17:10 +00001467 } else
1468#endif /* CTK_CONF_SCREENSAVER */
1469 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001470#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001471 /* If there is any change in the mouse conditions, find out in
1472 which window the mouse pointer currently is in order to send
1473 the correct signals, or bring a window to focus. */
1474 if(mouse_moved || mouse_button_changed) {
1475 ctk_mouse_show();
1476 screensaver_timer = 0;
1477
1478 if(myc == 0) {
1479 /* Here we should do whatever needs to be done when the mouse
1480 moves around and clicks in the menubar. */
1481 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001482 static unsigned char titlelen;
1483
adamdunkelsb2486562003-04-11 20:22:03 +00001484 /* Find out which menu that the mouse pointer is in. Start
1485 with the ->next menu after the desktop menu. We assume
1486 that the menus start one character from the left screen
1487 side and that the desktop menu is farthest to the
1488 right. */
1489 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001490 for(menu = menus.menus->next;
1491 menu != NULL; menu = menu->next) {
1492 titlelen = menu->titlelen;
1493 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001494 break;
adamdunkelse0683312003-04-09 09:02:52 +00001495 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001496 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001497 }
adamdunkelsb2486562003-04-11 20:22:03 +00001498
1499 /* Also check desktop menu. */
1500 if(mxc >= width - 7 &&
1501 mxc <= width - 1) {
1502 menu = &desktopmenu;
1503 }
1504
1505 menus.open = menu;
1506 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001507 }
adamdunkelse0683312003-04-09 09:02:52 +00001508 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001509 --myc;
1510
1511 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001512 static unsigned char nitems;
1513
adamdunkelsb2486562003-04-11 20:22:03 +00001514 /* Do whatever needs to be done when a menu is open. */
1515
adamdunkelscf90b0d2003-08-09 13:34:16 +00001516 /* First check if the mouse pointer is in the currently open
1517 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001518 if(menus.open == &desktopmenu) {
1519 menux = width - CTK_CONF_MENUWIDTH;
1520 } else {
1521 menux = 1;
1522 for(menu = menus.menus->next; menu != menus.open;
1523 menu = menu->next) {
1524 menux += menu->titlelen;
1525 }
1526 }
1527
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001528 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001529 /* Find out which of the menu items the mouse is pointing
1530 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001531 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1532 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001533 menus.open->active = myc;
1534 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001535 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001536 }
adamdunkelsb2486562003-04-11 20:22:03 +00001537 }
1538
1539 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001540 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001541 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001542 redraw |= activate_menu();
1543 } else {
1544 lastmenu = menus.open;
1545 menus.open = NULL;
1546 redraw |= REDRAW_MENUPART;
1547 }
1548 } else {
1549 redraw |= REDRAW_MENUS;
1550 }
1551 } else {
1552
adamdunkels965e2922003-06-30 20:44:57 +00001553 /* Walk through the windows from top to bottom to see in
1554 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001555 if(dialog != NULL) {
1556 window = dialog;
1557 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001558 for(window = windows; window != NULL;
1559 window = window->next) {
1560
adamdunkelsb2486562003-04-11 20:22:03 +00001561 /* Check if the mouse is within the window. */
1562 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001563 mxc <= window->x + window->w +
1564 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001565 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001566 myc <= window->y + window->h +
1567 ctk_draw_windowtitle_height +
1568 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001569 break;
1570 }
1571 }
1572 }
1573
1574
1575 /* If we didn't find any window, and there are no windows
1576 open, the mouse pointer will definately be within the
1577 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001578 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001579 window = &desktop_window;
1580 }
1581
adamdunkels965e2922003-06-30 20:44:57 +00001582 /* If the mouse pointer moves around outside of the
1583 currently focused window (or dialog), we should not have
1584 any focused widgets in the focused window so we make sure
1585 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001586 if(windows != NULL &&
1587 window != windows &&
1588 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001589 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001590 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001591 redraw |= REDRAW_WIDGETS;*/
1592 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001593 }
1594
1595 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001596 /* If the mouse was clicked outside of the current window,
1597 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001598 if(dialog == NULL &&
1599 window != &desktop_window &&
1600 window != windows &&
1601 mouse_clicked) {
1602 /* Bring window to front. */
1603 ctk_window_open(window);
1604 redraw |= REDRAW_ALL;
1605 } else {
1606
adamdunkels965e2922003-06-30 20:44:57 +00001607 /* Find out which widget currently is under the mouse
1608 pointer and give it focus, unless it already has
1609 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001610 mxc = mxc - window->x - ctk_draw_windowborder_width;
1611 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001612
adamdunkels965e2922003-06-30 20:44:57 +00001613 /* See if the mouse pointer is on a widget. If so, it
1614 should be selected and, if the button is clicked,
1615 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001616 for(widget = window->active; widget != NULL;
1617 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001618
adamdunkelsb2486562003-04-11 20:22:03 +00001619 if(mxc >= widget->x &&
1620 mxc <= widget->x + widget->w &&
1621 (myc == widget->y ||
1622 ((widget->type == CTK_WIDGET_BITMAP ||
1623 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1624 widget->type == CTK_WIDGET_ICON) &&
1625 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001626 myc <= widget->y +
1627 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001628 break;
1629 }
1630 }
1631
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001632
1633 /* if the mouse is moved in the focused window, we emit
1634 a ctk_signal_pointer_move signal to the owner of the
1635 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001636 if(mouse_moved &&
1637 (window != &desktop_window ||
1638 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001639
adamdunkels3b548c82004-07-04 11:41:39 +00001640 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001641
1642 /* If there was a focused widget that is not below the
1643 mouse pointer, we remove focus from the widget and
1644 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001645 if(window->focused != NULL &&
1646 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001647 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001648 if(CTK_WIDGET_TYPE(window->focused) ==
1649 CTK_WIDGET_TEXTENTRY) {
1650 ((struct ctk_textentry *)(window->focused))->state =
1651 CTK_TEXTENTRY_NORMAL;
1652 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001653 window->focused = NULL;*/
1654 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001655 }
1656 redraw |= REDRAW_WIDGETS;
1657 if(widget != NULL) {
1658 select_widget(widget);
1659 }
1660 }
1661
1662 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001663 ek_post(window->owner, ctk_signal_pointer_button,
1664 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001665 if(mouse_clicked && widget != NULL) {
1666 select_widget(widget);
1667 redraw |= activate(widget);
1668 }
1669 }
1670 }
1671 }
1672 }
adamdunkelsc4902862003-04-09 00:30:45 +00001673 }
1674 }
adamdunkels19a787c2003-04-09 09:22:24 +00001675#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001676
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001677 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001678
1679 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001680
1681 screensaver_timer = 0;
1682
adamdunkelsb2486562003-04-11 20:22:03 +00001683 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001684
1685 if(dialog != NULL) {
1686 window = dialog;
1687 } else if(windows != NULL) {
1688 window = windows;
1689 } else {
1690 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001691 }
1692
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001693 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001694
1695 if(widget != NULL &&
1696 widget->type == CTK_WIDGET_TEXTENTRY &&
1697 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1698 textentry_input(c, (struct ctk_textentry *)widget);
1699 add_redrawwidget(widget);
1700#if CTK_CONF_MENUS
1701 } else if(menus.open != NULL) {
1702 redraw |= menus_input(c);
1703#endif /* CTK_CONF_MENUS */
1704 } else {
1705 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001706 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001707 switch_focus_widget(DOWN);
1708 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001709 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001710 switch_focus_widget(UP);
1711 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001712#if CTK_CONF_MENUS
1713 case CTK_CONF_MENU_KEY:
1714 if(dialog == NULL) {
1715 if(lastmenu == NULL) {
1716 menus.open = menus.menus;
1717 } else {
1718 menus.open = lastmenu;
1719 }
1720 menus.open->active = 0;
1721 redraw |= REDRAW_MENUS;
1722 }
1723 break;
1724#endif /* CTK_CONF_MENUS */
1725 case CTK_CONF_WINDOWSWITCH_KEY:
1726 if(windows != NULL) {
1727 for(window = windows; window->next != NULL;
1728 window = window->next);
1729 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001730 }
1731 break;
1732 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001733
adamdunkels3af580f2003-08-11 22:27:13 +00001734 if(c == CH_ENTER &&
1735 widget != NULL) {
1736 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001737 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001738 if(widget != NULL &&
1739 widget->type == CTK_WIDGET_TEXTENTRY) {
1740 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1741 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001742 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001743 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001744 /* window->focused = NULL;*/
1745 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001746 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001747 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001748 }
1749 break;
1750 }
1751 }
1752
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001753#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001754 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001755 widgetptr = redraw_widgets;
1756 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001757 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001758 *widgetptr = NULL;
1759 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001760 }
1761 redraw &= ~REDRAW_WIDGETS;
1762 redraw_widgetptr = 0;
1763 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001764#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001765 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001766#if CTK_CONF_WINDOWMOVE
1767 } else if(mode == CTK_MODE_WINDOWMOVE) {
1768
1769 redraw = 0;
1770
1771 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001772
1773#if CTK_CONF_MOUSE_SUPPORT
1774
1775 /* If the mouse has moved, we move the window as well. */
1776 if(mouse_moved) {
1777
1778 if(window->w + mxc + 2 >= width) {
1779 window->x = width - 2 - window->w;
1780 } else {
1781 window->x = mxc;
1782 }
1783
adamdunkels3b548c82004-07-04 11:41:39 +00001784 if(window->h + myc + ctk_draw_windowtitle_height +
1785 ctk_draw_windowborder_height >= height) {
1786 window->y = height - window->h -
1787 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001788 } else {
1789 window->y = myc;
1790 }
1791 if(window->y > 0) {
1792 --window->y;
1793 }
1794
1795 redraw = REDRAW_ALL;
1796 }
1797
1798 /* Check if the mouse has been clicked, and stop moving the window
1799 if so. */
1800 if(mouse_button_changed &&
1801 mouse_button == 0) {
1802 mode = CTK_MODE_NORMAL;
1803 redraw = REDRAW_ALL;
1804 }
1805#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001806
1807 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1808
1809 screensaver_timer = 0;
1810
1811 c = ctk_arch_getkey();
1812
1813 switch(c) {
1814 case CH_CURS_RIGHT:
1815 ++window->x;
1816 if(window->x + window->w + 1 >= width) {
1817 --window->x;
1818 }
1819 redraw = REDRAW_ALL;
1820 break;
1821 case CH_CURS_LEFT:
1822 if(window->x > 0) {
1823 --window->x;
1824 }
1825 redraw = REDRAW_ALL;
1826 break;
1827 case CH_CURS_DOWN:
1828 ++window->y;
1829 if(window->y + window->h + 2 >= height) {
1830 --window->y;
1831 }
1832 redraw = REDRAW_ALL;
1833 break;
1834 case CH_CURS_UP:
1835 if(window->y > 0) {
1836 --window->y;
1837 }
1838 redraw = REDRAW_ALL;
1839 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001840 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001841 mode = CTK_MODE_NORMAL;
1842 redraw = REDRAW_ALL;
1843 break;
1844 }
1845 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001846#endif /* CTK_CONF_WINDOWMOVE */
1847 }
adamdunkelsb2486562003-04-11 20:22:03 +00001848
1849 if(redraw & REDRAW_ALL) {
1850 do_redraw_all(1, height);
1851#if CTK_CONF_MENUS
1852 } else if(redraw & REDRAW_MENUPART) {
1853 do_redraw_all(1, maxnitems + 1);
1854 } else if(redraw & REDRAW_MENUS) {
1855 ctk_draw_menus(&menus);
1856#endif /* CTK_CONF_MENUS */
1857 } else if(redraw & REDRAW_FOCUS) {
1858 if(dialog != NULL) {
1859 ctk_window_redraw(dialog);
1860 } else if(windows != NULL) {
1861 ctk_window_redraw(windows);
1862 } else {
1863 ctk_window_redraw(&desktop_window);
1864 }
1865 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001866 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001867 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001868 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001869 *widgetptr = NULL;
1870 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001871 }
1872 }
1873 redraw = 0;
1874 redraw_widgetptr = 0;
1875
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001876}
1877/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001878EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1879{
1880
1881}
1882/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001883/** @} */
1884/** @} */
1885