blob: f1e1ff85057057fa68fc0086c42defcedc16577f [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 *
adamdunkels6b9d5e82004-09-19 15:24:19 +000046 * $Id: ctk.c,v 1.42 2004/09/19 15:24:19 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;
adamdunkels6b9d5e82004-09-19 15:24:19 +00001073 if(focus == NULL) {
1074 return;
1075 }
adamdunkelse8bdfe12003-04-25 08:49:17 +00001076 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077 add_redrawwidget(focus);
1078
1079 if((direction & 1) == 0) {
1080 /* Move focus "up" */
1081 focus = focus->next;
1082 } else {
1083 /* Move focus "down" */
1084 for(widget = window->active;
1085 widget != NULL; widget = widget->next) {
1086 if(widget->next == focus) {
1087 break;
1088 }
1089 }
1090 focus = widget;
1091 if(focus == NULL) {
1092 if(window->active != NULL) {
1093 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001094 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001095 }
1096 }
1097 }
1098 if(focus == NULL) {
1099 focus = window->active;
1100 }
adamdunkelse0683312003-04-09 09:02:52 +00001101
adamdunkelsb2486562003-04-11 20:22:03 +00001102 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001103}
1104/*-----------------------------------------------------------------------------------*/
1105#if CTK_CONF_MENUS
1106static void
1107switch_open_menu(unsigned char rightleft)
1108{
1109 struct ctk_menu *menu;
1110
1111 if(rightleft == 0) {
1112 /* Move right */
1113 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1114 if(menu->next == menus.open) {
1115 break;
1116 }
1117 }
1118 lastmenu = menus.open;
1119 menus.open = menu;
1120 if(menus.open == NULL) {
1121 for(menu = menus.menus;
1122 menu->next != NULL; menu = menu->next);
1123 menus.open = menu;
1124 }
1125 } else {
1126 /* Move to left */
1127 lastmenu = menus.open;
1128 menus.open = menus.open->next;
1129 if(menus.open == NULL) {
1130 menus.open = menus.menus;
1131 }
1132 }
1133
adamdunkels66109622003-04-24 17:17:10 +00001134 menus.open->active = 0;
1135
1136 /* if(menus.open->nitems > maxnitems) {
1137 maxnitems = menus.open->nitems;
1138 }*/
1139
adamdunkels965e2922003-06-30 20:44:57 +00001140 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001141}
1142/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001143static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001144switch_menu_item(unsigned char updown)
1145{
1146 register struct ctk_menu *m;
1147
1148 m = menus.open;
1149
1150 if(updown == 0) {
1151 /* Move up */
1152 if(m->active == 0) {
1153 m->active = m->nitems - 1;
1154 } else {
1155 --m->active;
1156 if(m->items[m->active].title[0] == '-') {
1157 --m->active;
1158 }
1159 }
1160 } else {
1161 /* Move down */
1162 if(m->active >= m->nitems - 1) {
1163 m->active = 0;
1164 } else {
1165 ++m->active;
1166 if(m->items[m->active].title[0] == '-') {
1167 ++m->active;
1168 }
1169 }
1170 }
1171
1172}
1173#endif /* CTK_CONF_MENUS */
1174/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001175static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001176activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001177{
1178 static unsigned char len;
1179
1180 if(w->type == CTK_WIDGET_BUTTON) {
1181 if(w == (struct ctk_widget *)&windows->closebutton) {
1182#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001183 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001184 ctk_window_close(windows);
1185 return REDRAW_ALL;
1186#endif /* CTK_CONF_WINDOWCLOSE */
1187 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1188#if CTK_CONF_WINDOWCLOSE
1189 mode = CTK_MODE_WINDOWMOVE;
1190#endif /* CTK_CONF_WINDOWCLOSE */
1191 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001192 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001193 }
1194#if CTK_CONF_ICONS
1195 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001196 if(w->widget.icon.owner != EK_ID_NONE) {
1197 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1198 } else {
1199 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1200 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001201#endif /* CTK_CONF_ICONS */
1202 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001203 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001204 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1205 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1206 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1207 len = strlen(w->widget.textentry.text);
1208 if(w->widget.textentry.xpos > len) {
1209 w->widget.textentry.xpos = len;
1210 }
1211 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1212 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001213 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001214 }
1215 add_redrawwidget(w);
1216 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001217 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001218 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001219 }
1220 return REDRAW_NONE;
1221}
1222/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001223static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001224textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001225 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001226{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001227 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001228 static unsigned char len, txpos, typos, tlen;
1229
1230 txpos = t->xpos;
1231 typos = t->ypos;
1232 tlen = t->len;
1233
1234 cptr = &t->text[txpos + typos * tlen];
1235
1236 switch(c) {
1237 case CH_CURS_LEFT:
1238 if(txpos > 0) {
1239 --txpos;
1240 }
1241 break;
1242
1243 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001244 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001245 ++txpos;
1246 }
1247 break;
1248
1249 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001250 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001251 break;
1252
1253 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001254 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001255 if(txpos == tlen) {
1256 --txpos;
1257 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001258 break;
1259
1260 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001261 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1262 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001263 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001264 break;
1265
adamdunkels9795b2e2003-08-09 23:32:37 +00001266 case CTK_CONF_WIDGETDOWN_KEY:
1267 t->state = CTK_TEXTENTRY_NORMAL;
1268 switch_focus_widget(DOWN);
1269 break;
1270 case CTK_CONF_WIDGETUP_KEY:
1271 t->state = CTK_TEXTENTRY_NORMAL;
1272 switch_focus_widget(UP);
1273 break;
1274
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001275 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001276 len = tlen - txpos;
1277 if(c == CH_DEL) {
1278 if(len == 1 && *cptr != 0) {
1279 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001280 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001281 if(txpos > 0) {
1282 --txpos;
1283 strcpy(cptr - 1, cptr);
1284 }
1285 }
1286 } else {
1287 if(ctk_arch_isprint(c)) {
1288 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001289 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001290 while(cptr2 > cptr) {
1291 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001292 --cptr2;
1293 }
adamdunkelsc9619082004-06-06 06:19:25 +00001294 ++txpos;
1295 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001296 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001297 }
1298 }
1299 break;
1300 }
1301
1302 t->xpos = txpos;
1303 t->ypos = typos;
1304}
1305/*-----------------------------------------------------------------------------------*/
1306#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001307static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001308activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001309{
1310 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001311
adamdunkelsb2486562003-04-11 20:22:03 +00001312 lastmenu = menus.open;
1313 if(menus.open == &desktopmenu) {
1314 for(w = windows; w != NULL; w = w->next) {
1315 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1316 ctk_window_open(w);
1317 menus.open = NULL;
1318 return REDRAW_ALL;
1319 }
1320 }
1321 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001322 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001323 }
1324 menus.open = NULL;
1325 return REDRAW_MENUPART;
1326}
1327/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001328static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001329menus_input(ctk_arch_key_t c)
1330{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001331
1332 if(menus.open->nitems > maxnitems) {
1333 maxnitems = menus.open->nitems;
1334 }
1335
1336
1337 switch(c) {
1338 case CH_CURS_RIGHT:
1339 switch_open_menu(1);
1340
1341 return REDRAW_MENUPART;
1342
1343 case CH_CURS_DOWN:
1344 switch_menu_item(1);
1345 return REDRAW_MENUS;
1346
1347 case CH_CURS_LEFT:
1348 switch_open_menu(0);
1349 return REDRAW_MENUPART;
1350
1351 case CH_CURS_UP:
1352 switch_menu_item(0);
1353 return REDRAW_MENUS;
1354
1355 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001356 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001357
adamdunkels88ed9c42003-03-28 12:10:09 +00001358 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001359 lastmenu = menus.open;
1360 menus.open = NULL;
1361 return REDRAW_MENUPART;
1362 }
adamdunkelsb2486562003-04-11 20:22:03 +00001363
1364 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365}
1366#endif /* CTK_CONF_MENUS */
1367/*-----------------------------------------------------------------------------------*/
1368static void
adamdunkels3b548c82004-07-04 11:41:39 +00001369handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001370{
1371 if(mode == CTK_MODE_NORMAL) {
1372 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001373 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001374#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001375 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001376#ifdef CTK_SCREENSAVER_INIT
1377 CTK_SCREENSAVER_INIT();
1378#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001379
adamdunkelscf90b0d2003-08-09 13:34:16 +00001380#endif /* CTK_CONF_SCREENSAVER */
1381 screensaver_timer = 0;
1382 }
1383 }
1384}
1385/*-----------------------------------------------------------------------------------*/
1386static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001387unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1388{
1389 if(w != NULL) {
1390 redraw |= REDRAW_WIDGETS;
1391 add_redrawwidget(w);
1392 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1393 ((struct ctk_textentry *)w)->state =
1394 CTK_TEXTENTRY_NORMAL;
1395 }
1396 w->window->focused = NULL;
1397 }
1398}
1399/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001400EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001401{
1402 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001403 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001404 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001405 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001406 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001407#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001408 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1409 mouse_clicked;
1410 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001411 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001412
adamdunkels19a787c2003-04-09 09:22:24 +00001413#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001414
1415
adamdunkels3b548c82004-07-04 11:41:39 +00001416 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001417
adamdunkels9795b2e2003-08-09 23:32:37 +00001418 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001419 timer();
1420 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001421 } */
1422 if(timer_expired(&timer)) {
1423 timer_reset(&timer);
1424 handle_timer();
1425 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001426
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001427#if CTK_CONF_MENUS
1428 if(menus.open != NULL) {
1429 maxnitems = menus.open->nitems;
1430 } else {
1431 maxnitems = 0;
1432 }
1433#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001434
1435#if CTK_CONF_MOUSE_SUPPORT
1436 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1437
1438 /* See if there is any change in the buttons. */
1439 if(ctk_mouse_button() != mouse_button) {
1440 mouse_button = ctk_mouse_button();
1441 mouse_button_changed = 1;
1442 if(mouse_button == 0) {
1443 mouse_clicked = 1;
1444 }
1445 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001446
adamdunkelsb2486562003-04-11 20:22:03 +00001447 /* Check if the mouse pointer has moved. */
1448 if(ctk_mouse_x() != mouse_x ||
1449 ctk_mouse_y() != mouse_y) {
1450 mouse_x = ctk_mouse_x();
1451 mouse_y = ctk_mouse_y();
1452 mouse_moved = 1;
1453 }
1454
1455 mxc = ctk_mouse_xtoc(mouse_x);
1456 myc = ctk_mouse_ytoc(mouse_y);
1457#endif /* CTK_CONF_MOUSE_SUPPORT */
1458
1459
adamdunkels66109622003-04-24 17:17:10 +00001460#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001461 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001462 if(ctk_arch_keyavail()
1463#if CTK_CONF_MOUSE_SUPPORT
1464 || mouse_moved || mouse_button_changed
1465#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001466 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001467 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001468 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001469 }
adamdunkels66109622003-04-24 17:17:10 +00001470 } else
1471#endif /* CTK_CONF_SCREENSAVER */
1472 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001473#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001474 /* If there is any change in the mouse conditions, find out in
1475 which window the mouse pointer currently is in order to send
1476 the correct signals, or bring a window to focus. */
1477 if(mouse_moved || mouse_button_changed) {
1478 ctk_mouse_show();
1479 screensaver_timer = 0;
1480
1481 if(myc == 0) {
1482 /* Here we should do whatever needs to be done when the mouse
1483 moves around and clicks in the menubar. */
1484 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001485 static unsigned char titlelen;
1486
adamdunkelsb2486562003-04-11 20:22:03 +00001487 /* Find out which menu that the mouse pointer is in. Start
1488 with the ->next menu after the desktop menu. We assume
1489 that the menus start one character from the left screen
1490 side and that the desktop menu is farthest to the
1491 right. */
1492 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001493 for(menu = menus.menus->next;
1494 menu != NULL; menu = menu->next) {
1495 titlelen = menu->titlelen;
1496 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001497 break;
adamdunkelse0683312003-04-09 09:02:52 +00001498 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001499 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001500 }
adamdunkelsb2486562003-04-11 20:22:03 +00001501
1502 /* Also check desktop menu. */
1503 if(mxc >= width - 7 &&
1504 mxc <= width - 1) {
1505 menu = &desktopmenu;
1506 }
1507
1508 menus.open = menu;
1509 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001510 }
adamdunkelse0683312003-04-09 09:02:52 +00001511 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001512 --myc;
1513
1514 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001515 static unsigned char nitems;
1516
adamdunkelsb2486562003-04-11 20:22:03 +00001517 /* Do whatever needs to be done when a menu is open. */
1518
adamdunkelscf90b0d2003-08-09 13:34:16 +00001519 /* First check if the mouse pointer is in the currently open
1520 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001521 if(menus.open == &desktopmenu) {
1522 menux = width - CTK_CONF_MENUWIDTH;
1523 } else {
1524 menux = 1;
1525 for(menu = menus.menus->next; menu != menus.open;
1526 menu = menu->next) {
1527 menux += menu->titlelen;
1528 }
1529 }
1530
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001531 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001532 /* Find out which of the menu items the mouse is pointing
1533 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001534 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1535 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001536 menus.open->active = myc;
1537 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001538 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001539 }
adamdunkelsb2486562003-04-11 20:22:03 +00001540 }
1541
1542 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001543 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001544 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001545 redraw |= activate_menu();
1546 } else {
1547 lastmenu = menus.open;
1548 menus.open = NULL;
1549 redraw |= REDRAW_MENUPART;
1550 }
1551 } else {
1552 redraw |= REDRAW_MENUS;
1553 }
1554 } else {
1555
adamdunkels965e2922003-06-30 20:44:57 +00001556 /* Walk through the windows from top to bottom to see in
1557 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001558 if(dialog != NULL) {
1559 window = dialog;
1560 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001561 for(window = windows; window != NULL;
1562 window = window->next) {
1563
adamdunkelsb2486562003-04-11 20:22:03 +00001564 /* Check if the mouse is within the window. */
1565 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001566 mxc <= window->x + window->w +
1567 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001568 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001569 myc <= window->y + window->h +
1570 ctk_draw_windowtitle_height +
1571 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001572 break;
1573 }
1574 }
1575 }
1576
1577
1578 /* If we didn't find any window, and there are no windows
1579 open, the mouse pointer will definately be within the
1580 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001581 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001582 window = &desktop_window;
1583 }
1584
adamdunkels965e2922003-06-30 20:44:57 +00001585 /* If the mouse pointer moves around outside of the
1586 currently focused window (or dialog), we should not have
1587 any focused widgets in the focused window so we make sure
1588 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001589 if(windows != NULL &&
1590 window != windows &&
1591 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001592 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001593 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001594 redraw |= REDRAW_WIDGETS;*/
1595 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001596 }
1597
1598 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001599 /* If the mouse was clicked outside of the current window,
1600 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001601 if(dialog == NULL &&
1602 window != &desktop_window &&
1603 window != windows &&
1604 mouse_clicked) {
1605 /* Bring window to front. */
1606 ctk_window_open(window);
1607 redraw |= REDRAW_ALL;
1608 } else {
1609
adamdunkels965e2922003-06-30 20:44:57 +00001610 /* Find out which widget currently is under the mouse
1611 pointer and give it focus, unless it already has
1612 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001613 mxc = mxc - window->x - ctk_draw_windowborder_width;
1614 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001615
adamdunkels965e2922003-06-30 20:44:57 +00001616 /* See if the mouse pointer is on a widget. If so, it
1617 should be selected and, if the button is clicked,
1618 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001619 for(widget = window->active; widget != NULL;
1620 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001621
adamdunkelsb2486562003-04-11 20:22:03 +00001622 if(mxc >= widget->x &&
1623 mxc <= widget->x + widget->w &&
1624 (myc == widget->y ||
1625 ((widget->type == CTK_WIDGET_BITMAP ||
1626 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1627 widget->type == CTK_WIDGET_ICON) &&
1628 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001629 myc <= widget->y +
1630 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001631 break;
1632 }
1633 }
1634
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001635
1636 /* if the mouse is moved in the focused window, we emit
1637 a ctk_signal_pointer_move signal to the owner of the
1638 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001639 if(mouse_moved &&
1640 (window != &desktop_window ||
1641 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001642
adamdunkels3b548c82004-07-04 11:41:39 +00001643 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001644
1645 /* If there was a focused widget that is not below the
1646 mouse pointer, we remove focus from the widget and
1647 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001648 if(window->focused != NULL &&
1649 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001650 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001651 if(CTK_WIDGET_TYPE(window->focused) ==
1652 CTK_WIDGET_TEXTENTRY) {
1653 ((struct ctk_textentry *)(window->focused))->state =
1654 CTK_TEXTENTRY_NORMAL;
1655 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001656 window->focused = NULL;*/
1657 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001658 }
1659 redraw |= REDRAW_WIDGETS;
1660 if(widget != NULL) {
1661 select_widget(widget);
1662 }
1663 }
1664
1665 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001666 ek_post(window->owner, ctk_signal_pointer_button,
1667 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001668 if(mouse_clicked && widget != NULL) {
1669 select_widget(widget);
1670 redraw |= activate(widget);
1671 }
1672 }
1673 }
1674 }
1675 }
adamdunkelsc4902862003-04-09 00:30:45 +00001676 }
1677 }
adamdunkels19a787c2003-04-09 09:22:24 +00001678#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001679
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001680 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001681
1682 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001683
1684 screensaver_timer = 0;
1685
adamdunkelsb2486562003-04-11 20:22:03 +00001686 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001687
1688 if(dialog != NULL) {
1689 window = dialog;
1690 } else if(windows != NULL) {
1691 window = windows;
1692 } else {
1693 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001694 }
1695
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001696 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001697
1698 if(widget != NULL &&
1699 widget->type == CTK_WIDGET_TEXTENTRY &&
1700 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1701 textentry_input(c, (struct ctk_textentry *)widget);
1702 add_redrawwidget(widget);
1703#if CTK_CONF_MENUS
1704 } else if(menus.open != NULL) {
1705 redraw |= menus_input(c);
1706#endif /* CTK_CONF_MENUS */
1707 } else {
1708 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001709 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001710 switch_focus_widget(DOWN);
1711 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001712 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001713 switch_focus_widget(UP);
1714 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001715#if CTK_CONF_MENUS
1716 case CTK_CONF_MENU_KEY:
1717 if(dialog == NULL) {
1718 if(lastmenu == NULL) {
1719 menus.open = menus.menus;
1720 } else {
1721 menus.open = lastmenu;
1722 }
1723 menus.open->active = 0;
1724 redraw |= REDRAW_MENUS;
1725 }
1726 break;
1727#endif /* CTK_CONF_MENUS */
1728 case CTK_CONF_WINDOWSWITCH_KEY:
1729 if(windows != NULL) {
1730 for(window = windows; window->next != NULL;
1731 window = window->next);
1732 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001733 }
1734 break;
1735 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001736
adamdunkels3af580f2003-08-11 22:27:13 +00001737 if(c == CH_ENTER &&
1738 widget != NULL) {
1739 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001740 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001741 if(widget != NULL &&
1742 widget->type == CTK_WIDGET_TEXTENTRY) {
1743 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1744 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001745 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001746 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001747 /* window->focused = NULL;*/
1748 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001749 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001750 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001751 }
1752 break;
1753 }
1754 }
1755
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001756#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001757 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001758 widgetptr = redraw_widgets;
1759 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001760 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001761 *widgetptr = NULL;
1762 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001763 }
1764 redraw &= ~REDRAW_WIDGETS;
1765 redraw_widgetptr = 0;
1766 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001767#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001768 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001769#if CTK_CONF_WINDOWMOVE
1770 } else if(mode == CTK_MODE_WINDOWMOVE) {
1771
1772 redraw = 0;
1773
1774 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001775
1776#if CTK_CONF_MOUSE_SUPPORT
1777
1778 /* If the mouse has moved, we move the window as well. */
1779 if(mouse_moved) {
1780
1781 if(window->w + mxc + 2 >= width) {
1782 window->x = width - 2 - window->w;
1783 } else {
1784 window->x = mxc;
1785 }
1786
adamdunkels3b548c82004-07-04 11:41:39 +00001787 if(window->h + myc + ctk_draw_windowtitle_height +
1788 ctk_draw_windowborder_height >= height) {
1789 window->y = height - window->h -
1790 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001791 } else {
1792 window->y = myc;
1793 }
1794 if(window->y > 0) {
1795 --window->y;
1796 }
1797
1798 redraw = REDRAW_ALL;
1799 }
1800
1801 /* Check if the mouse has been clicked, and stop moving the window
1802 if so. */
1803 if(mouse_button_changed &&
1804 mouse_button == 0) {
1805 mode = CTK_MODE_NORMAL;
1806 redraw = REDRAW_ALL;
1807 }
1808#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001809
1810 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1811
1812 screensaver_timer = 0;
1813
1814 c = ctk_arch_getkey();
1815
1816 switch(c) {
1817 case CH_CURS_RIGHT:
1818 ++window->x;
1819 if(window->x + window->w + 1 >= width) {
1820 --window->x;
1821 }
1822 redraw = REDRAW_ALL;
1823 break;
1824 case CH_CURS_LEFT:
1825 if(window->x > 0) {
1826 --window->x;
1827 }
1828 redraw = REDRAW_ALL;
1829 break;
1830 case CH_CURS_DOWN:
1831 ++window->y;
1832 if(window->y + window->h + 2 >= height) {
1833 --window->y;
1834 }
1835 redraw = REDRAW_ALL;
1836 break;
1837 case CH_CURS_UP:
1838 if(window->y > 0) {
1839 --window->y;
1840 }
1841 redraw = REDRAW_ALL;
1842 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001843 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001844 mode = CTK_MODE_NORMAL;
1845 redraw = REDRAW_ALL;
1846 break;
1847 }
1848 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001849#endif /* CTK_CONF_WINDOWMOVE */
1850 }
adamdunkelsb2486562003-04-11 20:22:03 +00001851
1852 if(redraw & REDRAW_ALL) {
1853 do_redraw_all(1, height);
1854#if CTK_CONF_MENUS
1855 } else if(redraw & REDRAW_MENUPART) {
1856 do_redraw_all(1, maxnitems + 1);
1857 } else if(redraw & REDRAW_MENUS) {
1858 ctk_draw_menus(&menus);
1859#endif /* CTK_CONF_MENUS */
1860 } else if(redraw & REDRAW_FOCUS) {
1861 if(dialog != NULL) {
1862 ctk_window_redraw(dialog);
1863 } else if(windows != NULL) {
1864 ctk_window_redraw(windows);
1865 } else {
1866 ctk_window_redraw(&desktop_window);
1867 }
1868 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001869 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001870 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001871 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001872 *widgetptr = NULL;
1873 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001874 }
1875 }
1876 redraw = 0;
1877 redraw_widgetptr = 0;
1878
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001879}
1880/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001881EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1882{
1883
1884}
1885/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001886/** @} */
1887/** @} */
1888