blob: 330f76ede870e8302d0c50d3805f3fb5b41faaaa [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 *
oliverschmidtf28743b2005-05-04 22:33:45 +000046 * $Id: ctk.c,v 1.48 2005/05/04 22:33:45 oliverschmidt 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;
oliverschmidte99386b2004-12-27 22:03:04 +0000626 unsigned char focus;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000627
628 if(mode != CTK_MODE_NORMAL &&
629 mode != CTK_MODE_WINDOWMOVE) {
630 return;
631 }
632
633 ctk_draw_clear(clipy1, clipy2);
634
635 /* Draw widgets in root window */
636 for(widget = desktop_window.active;
637 widget != NULL; widget = widget->next) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000638 ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000639 }
640
641 /* Draw windows */
642 if(windows != NULL) {
643 /* Find the last window.*/
644 for(w = windows; w->next != NULL; w = w->next);
645
646 /* Draw the windows from back to front. */
647 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000648 ctk_draw_clear_window(w, 0, clipy1, clipy2);
oliverschmidtadf27db2005-03-15 15:51:17 +0000649 ctk_draw_window(w, 0, clipy1, clipy2, 1);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000650 }
oliverschmidte99386b2004-12-27 22:03:04 +0000651
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000652 /* Draw focused window */
oliverschmidte99386b2004-12-27 22:03:04 +0000653 focus = mode == CTK_MODE_WINDOWMOVE?
654 CTK_FOCUS_WIDGET|CTK_FOCUS_WINDOW:
655 CTK_FOCUS_WINDOW;
656 ctk_draw_clear_window(windows, focus, clipy1, clipy2);
oliverschmidtadf27db2005-03-15 15:51:17 +0000657 ctk_draw_window(windows, focus, clipy1, clipy2, 1);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000658 }
659
660 /* Draw dialog (if any) */
661 if(dialog != NULL) {
662 ctk_draw_dialog(dialog);
663 }
664
665#if CTK_CONF_MENUS
666 ctk_draw_menus(&menus);
667#endif /* CTK_CONF_MENUS */
668}
669/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000670/**
671 * Redraw the entire desktop.
672 *
673 * \param d The desktop to be redrawn.
674 *
675 * \note Currently the parameter d is not used, but must be set to
676 * NULL.
adamdunkelse937ded2003-10-01 07:53:57 +0000677 *
adamdunkels35298692003-08-31 22:16:49 +0000678 */
679/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000680void
adamdunkels965e2922003-06-30 20:44:57 +0000681ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000682{
adamdunkels3b548c82004-07-04 11:41:39 +0000683 if(EK_CURRENT() == &p) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000684 if(mode == CTK_MODE_NORMAL ||
685 mode == CTK_MODE_WINDOWMOVE) {
686 do_redraw_all(1, height);
687 }
688 } else {
689 redraw |= REDRAW_ALL;
690 }
691}
692/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000693/**
694 * Redraw a window.
695 *
696 * This function redraws the window, but only if it is the foremost
697 * one on the desktop.
698 *
699 * \param w The window to be redrawn.
700 */
701/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000702void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000703ctk_window_redraw(struct ctk_window *w)
704{
705 /* Only redraw the window if it is a dialog or if it is the foremost
706 window. */
707 if(mode != CTK_MODE_NORMAL) {
708 return;
709 }
710
711 if(w == dialog) {
712 ctk_draw_dialog(w);
713 } else if(dialog == NULL &&
714#if CTK_CONF_MENUS
715 menus.open == NULL &&
716#endif /* CTK_CONF_MENUS */
717 windows == w) {
718 ctk_draw_window(w, CTK_FOCUS_WINDOW,
oliverschmidtadf27db2005-03-15 15:51:17 +0000719 0, height, 0);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000720 }
721}
722/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000723/**
724 * \internal Creates a new window.
725 *
726 * \param window The window to be created.
727 * \param w The width of the window.
728 * \param h The height of the window.
729 * \param title The title of the window.
730 */
731/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000732static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000733window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000734 unsigned char w, unsigned char h,
735 char *title)
736{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000737
738 if(w >= width - 2) {
739 window->x = 0;
740 } else {
741 window->x = (width - w - 2) / 2;
742 }
oliverschmidt432bc5a2004-12-22 22:52:53 +0000743 if(h >= height - 2 - ctk_draw_windowtitle_height) {
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000744 window->y = 0;
745 } else {
oliverschmidt432bc5a2004-12-22 22:52:53 +0000746 window->y = (height - h - 2 - ctk_draw_windowtitle_height) / 2;
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000747 }
748
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000749 window->w = w;
750 window->h = h;
751 window->title = title;
752 if(title != NULL) {
753 window->titlelen = strlen(title);
754 } else {
755 window->titlelen = 0;
756 }
757 window->next = window->prev = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000758 /* window->owner = DISPATCHER_CURRENT();*/
759 window->owner = EK_PROC_ID(EK_CURRENT());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000760 window->active = window->inactive = window->focused = NULL;
761}
762/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000763/**
764 * Create a new window.
765 *
766 * Creates a new window. The memory for the window structure must
767 * already be allocated by the caller, and is usually done with a
768 * static declaration.
769 *
770 * This function sets up the internal structure of the ctk_window
771 * struct and creates the move and close buttons, but it does not open
772 * the window. The window must be explicitly opened by calling the
773 * ctk_window_open() function.
774 *
775 * \param window The window to be created.
776 * \param w The width of the new window.
777 * \param h The height of the new window.
778 * \param title The title of the new window.
779 */
780/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781void
782ctk_window_new(struct ctk_window *window,
783 unsigned char w, unsigned char h,
784 char *title)
785{
786 window_new(window, w, h, title);
787
788 make_windowbuttons(window);
789}
790/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000791/**
792 * Creates a new dialog.
793 *
794 * This function only sets up the internal structure of the ctk_window
795 * struct but does not open the dialog. The dialog must be explicitly
796 * opened by calling the ctk_dialog_open() function.
797 *
798 * \param dialog The dialog to be created.
799 * \param w The width of the dialog.
800 * \param h The height of the dialog.
801 */
802/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000803void
adamdunkels35298692003-08-31 22:16:49 +0000804ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805 unsigned char w, unsigned char h)
806{
adamdunkels35298692003-08-31 22:16:49 +0000807 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808}
adamdunkels3af580f2003-08-11 22:27:13 +0000809/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000810/**
811 * Creates a new menu.
812 *
813 * This function sets up the internal structure of the menu, but does
814 * not add it to the menubar. Use the function ctk_menu_add() for that
815 * purpose.
816 *
817 * \param menu The menu to be created.
818 * \param title The title of the menu.
819 */
820/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000821void
adamdunkelsd07a5422003-04-05 12:22:35 +0000822ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000823 char *title)
824{
825#if CTK_CONF_MENUS
826 menu->next = NULL;
827 menu->title = title;
828 menu->titlelen = strlen(title);
829 menu->active = 0;
830 menu->nitems = 0;
831#endif /* CTK_CONF_MENUS */
832}
833/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000834/**
835 * Adds a menu item to a menu.
836 *
837 * In CTK, each menu item is identified by a number which is unique
838 * within each menu. When a menu item is selected, a
839 * ctk_menuitem_activated signal is emitted and the menu item number
840 * is passed as signal data with the signal.
841 *
842 * \param menu The menu to which the menu item should be added.
843 * \param name The name of the menu item.
844 * \return The number of the menu item.
845 */
846/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000847unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000848ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849 char *name)
850{
851#if CTK_CONF_MENUS
852 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
853 return 0;
854 }
855 menu->items[menu->nitems].title = name;
856 menu->items[menu->nitems].titlelen = strlen(name);
857 return menu->nitems++;
858#else
859 return 0;
860#endif /* CTK_CONF_MENUS */
861}
862/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000863/**
864 * \internal Adds a widget to the list of widgets that should be
865 * redrawn.
866 *
867 * \param w The widget that should be redrawn.
868 */
869/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000870static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000871add_redrawwidget(struct ctk_widget *w)
872{
873 static unsigned char i;
874
875 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
876 redraw |= REDRAW_FOCUS;
877 } else {
878 redraw |= REDRAW_WIDGETS;
879 /* Check if it is in the queue already. If so, we don't add it
880 again. */
881 for(i = 0; i < redraw_widgetptr; ++i) {
882 if(redraw_widgets[i] == w) {
883 return;
884 }
885 }
886 redraw_widgets[redraw_widgetptr++] = w;
887 }
888}
889/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000890/**
891 * \internal Checks if a widget redrawn and adds it to the list of
892 * widgets to be redrawn.
893 *
894 * A widget can be redrawn only if the current CTK mode is
895 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
896 * foremost window.
897 *
898 * \param widget The widget that should be redrawn.
899 */
900/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000901static void
902widget_redraw(struct ctk_widget *widget)
903{
904 struct ctk_window *window;
905
906 if(mode != CTK_MODE_NORMAL || widget == NULL) {
907 return;
908 }
909
910 /* Only redraw widgets that are in the foremost window. If we would
911 allow redrawing widgets in non-focused windows, we would have to
912 redraw all the windows that cover the non-focused window as well,
913 which would lead to flickering.
914
915 Also, we avoid drawing any widgets when the menus are active.
916 */
917
918#if CTK_CONF_MENUS
919 if(menus.open == NULL)
920#endif /* CTK_CONF_MENUS */
921 {
922 window = widget->window;
923 if(window == dialog) {
924 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
925 } else if(dialog == NULL &&
926 (window == windows ||
927 window == &desktop_window)) {
928 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
929 }
930 }
931}
932/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000933/**
934 * Redraws a widget.
935 *
936 * This function will set a flag which causes the widget to be redrawn
937 * next time the CTK process is scheduled.
938 *
939 * \param widget The widget that is to be redrawn.
940 *
941 * \note This function should usually not be called directly since it
942 * requires typecasting of the widget parameter. The wrapper macro
943 * CTK_WIDGET_REDRAW() does the required typecast and should be used
944 * instead.
945 */
946/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000947void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000948ctk_widget_redraw(struct ctk_widget *widget)
949{
adamdunkels9f667f22003-04-16 18:29:19 +0000950 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000951 return;
952 }
953
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000954 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000955 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000956 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000957}
958/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000959/**
960 * Adds a widget to a window.
961 *
962 * This function adds a widget to a window. The order of which the
963 * widgets are added is important, as it sets the order to which
964 * widgets are cycled with the widget selection keys.
965 *
966 * \param window The window to which the widhet should be added.
967 * \param widget The widget to be added.
968 */
969/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000970void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000971ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
972 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000973{
974 if(widget->type == CTK_WIDGET_LABEL ||
975 widget->type == CTK_WIDGET_SEPARATOR) {
976 widget->next = window->inactive;
977 window->inactive = widget;
978 widget->window = window;
979 } else {
980 widget->next = window->active;
981 window->active = widget;
982 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000983 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000984 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000985 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986 }
987}
988/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000989/**
990 * Gets the width of the desktop.
991 *
992 * \param d The desktop.
993 * \return The width of the desktop, in characters.
994 *
995 * \note The d parameter is currently unused and must be set to NULL.
996 */
997/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000998unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000999ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001000{
1001 return ctk_draw_width();
1002}
1003/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +00001004/**
1005 * Gets the height of the desktop.
1006 *
1007 * \param d The desktop.
1008 * \return The height of the desktop, in characters.
1009 *
1010 * \note The d parameter is currently unused and must be set to NULL.
1011 */
1012/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001013unsigned char
adamdunkels35298692003-08-31 22:16:49 +00001014ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001015{
1016 return ctk_draw_height();
1017}
1018/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +00001019/**
1020 * \internal Selects a widget in the window of the widget.
1021 *
1022 * \param focus The widget to be focused.
1023 */
1024/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001025static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +00001026select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +00001027{
1028 struct ctk_window *window;
1029
1030 window = focus->window;
1031
1032 if(focus != window->focused) {
1033 window->focused = focus;
1034 /* The operation changed the focus, so we emit a "hover" signal
1035 for those widgets that support it. */
1036
1037 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001038 ek_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001039 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001040 ek_post(window->owner, ctk_signal_button_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001041 }
1042
1043 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +00001044
adamdunkels3b548c82004-07-04 11:41:39 +00001045 ek_post(focus->window->owner, ctk_signal_widget_select, focus);
adamdunkels58917a82003-04-18 00:18:38 +00001046
adamdunkelse0683312003-04-09 09:02:52 +00001047 }
1048
1049}
1050/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001051#define UP 0
1052#define DOWN 1
1053#define LEFT 2
1054#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +00001055static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001056switch_focus_widget(unsigned char direction)
1057{
1058 register struct ctk_window *window;
1059 register struct ctk_widget *focus;
1060 struct ctk_widget *widget;
1061
1062
1063 if(dialog != NULL) {
1064 window = dialog;
1065 } else {
1066 window = windows;
1067 }
1068
1069 /* If there are no windows open, we move focus around between the
1070 icons on the root window instead. */
1071 if(window == NULL) {
1072 window = &desktop_window;
1073 }
1074
1075 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +00001076 if(focus == NULL) {
1077 focus = window->active;
adamdunkels6b9d5e82004-09-19 15:24:19 +00001078 if(focus == NULL) {
1079 return;
1080 }
adamdunkelse8bdfe12003-04-25 08:49:17 +00001081 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001082 add_redrawwidget(focus);
1083
1084 if((direction & 1) == 0) {
1085 /* Move focus "up" */
1086 focus = focus->next;
1087 } else {
1088 /* Move focus "down" */
1089 for(widget = window->active;
1090 widget != NULL; widget = widget->next) {
1091 if(widget->next == focus) {
1092 break;
1093 }
1094 }
1095 focus = widget;
1096 if(focus == NULL) {
1097 if(window->active != NULL) {
1098 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001099 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001100 }
1101 }
1102 }
1103 if(focus == NULL) {
1104 focus = window->active;
1105 }
adamdunkelse0683312003-04-09 09:02:52 +00001106
adamdunkelsb2486562003-04-11 20:22:03 +00001107 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001108}
1109/*-----------------------------------------------------------------------------------*/
1110#if CTK_CONF_MENUS
1111static void
1112switch_open_menu(unsigned char rightleft)
1113{
1114 struct ctk_menu *menu;
1115
1116 if(rightleft == 0) {
1117 /* Move right */
1118 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1119 if(menu->next == menus.open) {
1120 break;
1121 }
1122 }
1123 lastmenu = menus.open;
1124 menus.open = menu;
1125 if(menus.open == NULL) {
1126 for(menu = menus.menus;
1127 menu->next != NULL; menu = menu->next);
1128 menus.open = menu;
1129 }
1130 } else {
1131 /* Move to left */
1132 lastmenu = menus.open;
1133 menus.open = menus.open->next;
1134 if(menus.open == NULL) {
1135 menus.open = menus.menus;
1136 }
1137 }
1138
adamdunkels66109622003-04-24 17:17:10 +00001139 menus.open->active = 0;
1140
1141 /* if(menus.open->nitems > maxnitems) {
1142 maxnitems = menus.open->nitems;
1143 }*/
1144
adamdunkels965e2922003-06-30 20:44:57 +00001145 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001146}
1147/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001148static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001149switch_menu_item(unsigned char updown)
1150{
1151 register struct ctk_menu *m;
1152
1153 m = menus.open;
1154
1155 if(updown == 0) {
1156 /* Move up */
1157 if(m->active == 0) {
1158 m->active = m->nitems - 1;
1159 } else {
1160 --m->active;
1161 if(m->items[m->active].title[0] == '-') {
1162 --m->active;
1163 }
1164 }
1165 } else {
1166 /* Move down */
1167 if(m->active >= m->nitems - 1) {
1168 m->active = 0;
1169 } else {
1170 ++m->active;
1171 if(m->items[m->active].title[0] == '-') {
1172 ++m->active;
1173 }
1174 }
1175 }
1176
1177}
1178#endif /* CTK_CONF_MENUS */
1179/*-----------------------------------------------------------------------------------*/
oliverschmidtf28743b2005-05-04 22:33:45 +00001180static void CC_FASTCALL
1181textentry_edit(CC_REGISTER_ARG struct ctk_textentry *t)
1182{
1183 t->state = CTK_TEXTENTRY_EDIT;
1184 t->xpos = strlen(t->text);
1185 if(t->xpos == t->len) {
1186 --t->xpos;
1187 }
1188}
1189/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001190static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001191activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001192{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001193 if(w->type == CTK_WIDGET_BUTTON) {
1194 if(w == (struct ctk_widget *)&windows->closebutton) {
1195#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001196 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001197 ctk_window_close(windows);
1198 return REDRAW_ALL;
1199#endif /* CTK_CONF_WINDOWCLOSE */
1200 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
oliverschmidte99386b2004-12-27 22:03:04 +00001201#if CTK_CONF_WINDOWMOVE
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001202 mode = CTK_MODE_WINDOWMOVE;
oliverschmidte99386b2004-12-27 22:03:04 +00001203 return REDRAW_ALL;
1204#endif /* CTK_CONF_WINDOWMOVE */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001205 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001206 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001207 }
1208#if CTK_CONF_ICONS
1209 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001210 if(w->widget.icon.owner != EK_ID_NONE) {
1211 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1212 } else {
1213 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1214 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001215#endif /* CTK_CONF_ICONS */
1216 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001217 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1219 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
oliverschmidtf28743b2005-05-04 22:33:45 +00001220 textentry_edit((struct ctk_textentry *)w);
1221 } else {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001222 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001223 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001224 }
1225 add_redrawwidget(w);
1226 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001227 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001228 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001229 }
1230 return REDRAW_NONE;
1231}
1232/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001233static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001234textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001235 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001236{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001237 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001238 static unsigned char len, txpos, typos, tlen;
1239
oliverschmidt0096f6a2005-05-04 21:50:17 +00001240 if(t->input != NULL && t->input(c, t)) {
1241 return;
1242 }
1243
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001244 txpos = t->xpos;
1245 typos = t->ypos;
1246 tlen = t->len;
1247
1248 cptr = &t->text[txpos + typos * tlen];
1249
1250 switch(c) {
1251 case CH_CURS_LEFT:
1252 if(txpos > 0) {
1253 --txpos;
1254 }
1255 break;
1256
1257 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001258 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001259 ++txpos;
1260 }
1261 break;
1262
1263 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001264 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001265 break;
1266
1267 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001268 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001269 if(txpos == tlen) {
1270 --txpos;
1271 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272 break;
1273
1274 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001275 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1276 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001277 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001278 break;
1279
adamdunkels9795b2e2003-08-09 23:32:37 +00001280 case CTK_CONF_WIDGETDOWN_KEY:
1281 t->state = CTK_TEXTENTRY_NORMAL;
1282 switch_focus_widget(DOWN);
1283 break;
1284 case CTK_CONF_WIDGETUP_KEY:
1285 t->state = CTK_TEXTENTRY_NORMAL;
1286 switch_focus_widget(UP);
1287 break;
1288
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001289 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001290 len = tlen - txpos;
1291 if(c == CH_DEL) {
1292 if(len == 1 && *cptr != 0) {
1293 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001294 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001295 if(txpos > 0) {
1296 --txpos;
1297 strcpy(cptr - 1, cptr);
1298 }
1299 }
1300 } else {
1301 if(ctk_arch_isprint(c)) {
1302 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001303 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001304 while(cptr2 > cptr) {
1305 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001306 --cptr2;
1307 }
adamdunkelsc9619082004-06-06 06:19:25 +00001308 ++txpos;
1309 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001310 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001311 }
1312 }
1313 break;
1314 }
1315
1316 t->xpos = txpos;
1317 t->ypos = typos;
1318}
1319/*-----------------------------------------------------------------------------------*/
1320#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001321static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001322activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001323{
1324 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001325
adamdunkelsb2486562003-04-11 20:22:03 +00001326 lastmenu = menus.open;
1327 if(menus.open == &desktopmenu) {
1328 for(w = windows; w != NULL; w = w->next) {
1329 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1330 ctk_window_open(w);
1331 menus.open = NULL;
1332 return REDRAW_ALL;
1333 }
1334 }
1335 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001336 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001337 }
1338 menus.open = NULL;
1339 return REDRAW_MENUPART;
1340}
1341/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001342static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001343menus_input(ctk_arch_key_t c)
1344{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001345
1346 if(menus.open->nitems > maxnitems) {
1347 maxnitems = menus.open->nitems;
1348 }
1349
1350
1351 switch(c) {
1352 case CH_CURS_RIGHT:
1353 switch_open_menu(1);
1354
1355 return REDRAW_MENUPART;
1356
1357 case CH_CURS_DOWN:
1358 switch_menu_item(1);
1359 return REDRAW_MENUS;
1360
1361 case CH_CURS_LEFT:
1362 switch_open_menu(0);
1363 return REDRAW_MENUPART;
1364
1365 case CH_CURS_UP:
1366 switch_menu_item(0);
1367 return REDRAW_MENUS;
1368
1369 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001370 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001371
adamdunkels88ed9c42003-03-28 12:10:09 +00001372 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001373 lastmenu = menus.open;
1374 menus.open = NULL;
1375 return REDRAW_MENUPART;
1376 }
adamdunkelsb2486562003-04-11 20:22:03 +00001377
1378 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001379}
1380#endif /* CTK_CONF_MENUS */
1381/*-----------------------------------------------------------------------------------*/
1382static void
adamdunkels3b548c82004-07-04 11:41:39 +00001383handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001384{
1385 if(mode == CTK_MODE_NORMAL) {
1386 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001387 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001388#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001389 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001390#ifdef CTK_SCREENSAVER_INIT
1391 CTK_SCREENSAVER_INIT();
1392#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001393
adamdunkelscf90b0d2003-08-09 13:34:16 +00001394#endif /* CTK_CONF_SCREENSAVER */
1395 screensaver_timer = 0;
1396 }
1397 }
1398}
1399/*-----------------------------------------------------------------------------------*/
1400static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001401unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1402{
1403 if(w != NULL) {
1404 redraw |= REDRAW_WIDGETS;
1405 add_redrawwidget(w);
1406 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1407 ((struct ctk_textentry *)w)->state =
1408 CTK_TEXTENTRY_NORMAL;
1409 }
1410 w->window->focused = NULL;
1411 }
1412}
1413/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001414EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001415{
1416 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001417 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001418 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001419 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001420 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001421#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001422 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1423 mouse_clicked;
1424 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001425 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001426
adamdunkels19a787c2003-04-09 09:22:24 +00001427#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001428
1429
adamdunkels3b548c82004-07-04 11:41:39 +00001430 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001431
adamdunkels9795b2e2003-08-09 23:32:37 +00001432 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001433 timer();
1434 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001435 } */
1436 if(timer_expired(&timer)) {
1437 timer_reset(&timer);
1438 handle_timer();
1439 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001440
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001441#if CTK_CONF_MENUS
1442 if(menus.open != NULL) {
1443 maxnitems = menus.open->nitems;
1444 } else {
1445 maxnitems = 0;
1446 }
1447#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001448
1449#if CTK_CONF_MOUSE_SUPPORT
1450 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1451
1452 /* See if there is any change in the buttons. */
1453 if(ctk_mouse_button() != mouse_button) {
1454 mouse_button = ctk_mouse_button();
1455 mouse_button_changed = 1;
1456 if(mouse_button == 0) {
1457 mouse_clicked = 1;
1458 }
1459 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001460
adamdunkelsb2486562003-04-11 20:22:03 +00001461 /* Check if the mouse pointer has moved. */
1462 if(ctk_mouse_x() != mouse_x ||
1463 ctk_mouse_y() != mouse_y) {
1464 mouse_x = ctk_mouse_x();
1465 mouse_y = ctk_mouse_y();
1466 mouse_moved = 1;
1467 }
1468
1469 mxc = ctk_mouse_xtoc(mouse_x);
1470 myc = ctk_mouse_ytoc(mouse_y);
1471#endif /* CTK_CONF_MOUSE_SUPPORT */
1472
1473
adamdunkels66109622003-04-24 17:17:10 +00001474#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001475 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001476 if(ctk_arch_keyavail()
1477#if CTK_CONF_MOUSE_SUPPORT
1478 || mouse_moved || mouse_button_changed
1479#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001480 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001481 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001482 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001483 }
adamdunkels66109622003-04-24 17:17:10 +00001484 } else
1485#endif /* CTK_CONF_SCREENSAVER */
1486 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001487#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001488 /* If there is any change in the mouse conditions, find out in
1489 which window the mouse pointer currently is in order to send
1490 the correct signals, or bring a window to focus. */
1491 if(mouse_moved || mouse_button_changed) {
1492 ctk_mouse_show();
1493 screensaver_timer = 0;
1494
1495 if(myc == 0) {
1496 /* Here we should do whatever needs to be done when the mouse
1497 moves around and clicks in the menubar. */
1498 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001499 static unsigned char titlelen;
1500
adamdunkelsb2486562003-04-11 20:22:03 +00001501 /* Find out which menu that the mouse pointer is in. Start
1502 with the ->next menu after the desktop menu. We assume
1503 that the menus start one character from the left screen
1504 side and that the desktop menu is farthest to the
1505 right. */
1506 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001507 for(menu = menus.menus->next;
1508 menu != NULL; menu = menu->next) {
1509 titlelen = menu->titlelen;
1510 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001511 break;
adamdunkelse0683312003-04-09 09:02:52 +00001512 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001513 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001514 }
adamdunkelsb2486562003-04-11 20:22:03 +00001515
1516 /* Also check desktop menu. */
1517 if(mxc >= width - 7 &&
1518 mxc <= width - 1) {
1519 menu = &desktopmenu;
1520 }
1521
1522 menus.open = menu;
1523 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001524 }
adamdunkelse0683312003-04-09 09:02:52 +00001525 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001526 --myc;
1527
1528 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001529 static unsigned char nitems;
1530
adamdunkelsb2486562003-04-11 20:22:03 +00001531 /* Do whatever needs to be done when a menu is open. */
1532
adamdunkelscf90b0d2003-08-09 13:34:16 +00001533 /* First check if the mouse pointer is in the currently open
1534 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001535 if(menus.open == &desktopmenu) {
1536 menux = width - CTK_CONF_MENUWIDTH;
1537 } else {
1538 menux = 1;
1539 for(menu = menus.menus->next; menu != menus.open;
1540 menu = menu->next) {
1541 menux += menu->titlelen;
1542 }
1543 }
1544
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001545 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001546 /* Find out which of the menu items the mouse is pointing
1547 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001548 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1549 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001550 menus.open->active = myc;
1551 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001553 }
adamdunkelsb2486562003-04-11 20:22:03 +00001554 }
1555
1556 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001557 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001558 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001559 redraw |= activate_menu();
1560 } else {
1561 lastmenu = menus.open;
1562 menus.open = NULL;
1563 redraw |= REDRAW_MENUPART;
1564 }
1565 } else {
1566 redraw |= REDRAW_MENUS;
1567 }
1568 } else {
1569
adamdunkels965e2922003-06-30 20:44:57 +00001570 /* Walk through the windows from top to bottom to see in
1571 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001572 if(dialog != NULL) {
1573 window = dialog;
1574 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001575 for(window = windows; window != NULL;
1576 window = window->next) {
1577
adamdunkelsb2486562003-04-11 20:22:03 +00001578 /* Check if the mouse is within the window. */
1579 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001580 mxc <= window->x + window->w +
1581 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001582 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001583 myc <= window->y + window->h +
1584 ctk_draw_windowtitle_height +
1585 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001586 break;
1587 }
1588 }
1589 }
1590
1591
1592 /* If we didn't find any window, and there are no windows
1593 open, the mouse pointer will definately be within the
1594 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001595 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001596 window = &desktop_window;
1597 }
1598
adamdunkels965e2922003-06-30 20:44:57 +00001599 /* If the mouse pointer moves around outside of the
1600 currently focused window (or dialog), we should not have
1601 any focused widgets in the focused window so we make sure
1602 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001603 if(windows != NULL &&
1604 window != windows &&
1605 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001606 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001607 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001608 redraw |= REDRAW_WIDGETS;*/
1609 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001610 }
1611
1612 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001613 /* If the mouse was clicked outside of the current window,
1614 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001615 if(dialog == NULL &&
1616 window != &desktop_window &&
1617 window != windows &&
1618 mouse_clicked) {
1619 /* Bring window to front. */
1620 ctk_window_open(window);
1621 redraw |= REDRAW_ALL;
1622 } else {
1623
adamdunkels965e2922003-06-30 20:44:57 +00001624 /* Find out which widget currently is under the mouse
1625 pointer and give it focus, unless it already has
1626 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001627 mxc = mxc - window->x - ctk_draw_windowborder_width;
1628 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001629
adamdunkels965e2922003-06-30 20:44:57 +00001630 /* See if the mouse pointer is on a widget. If so, it
1631 should be selected and, if the button is clicked,
1632 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001633 for(widget = window->active; widget != NULL;
1634 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001635
adamdunkelsb2486562003-04-11 20:22:03 +00001636 if(mxc >= widget->x &&
1637 mxc <= widget->x + widget->w &&
1638 (myc == widget->y ||
1639 ((widget->type == CTK_WIDGET_BITMAP ||
1640 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1641 widget->type == CTK_WIDGET_ICON) &&
1642 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001643 myc <= widget->y +
1644 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001645 break;
1646 }
1647 }
1648
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001649
1650 /* if the mouse is moved in the focused window, we emit
1651 a ctk_signal_pointer_move signal to the owner of the
1652 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001653 if(mouse_moved &&
1654 (window != &desktop_window ||
1655 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001656
adamdunkels3b548c82004-07-04 11:41:39 +00001657 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001658
1659 /* If there was a focused widget that is not below the
1660 mouse pointer, we remove focus from the widget and
1661 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001662 if(window->focused != NULL &&
1663 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001664 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001665 if(CTK_WIDGET_TYPE(window->focused) ==
1666 CTK_WIDGET_TEXTENTRY) {
1667 ((struct ctk_textentry *)(window->focused))->state =
1668 CTK_TEXTENTRY_NORMAL;
1669 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001670 window->focused = NULL;*/
1671 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001672 }
1673 redraw |= REDRAW_WIDGETS;
1674 if(widget != NULL) {
1675 select_widget(widget);
1676 }
1677 }
1678
1679 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001680 ek_post(window->owner, ctk_signal_pointer_button,
1681 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001682 if(mouse_clicked && widget != NULL) {
1683 select_widget(widget);
1684 redraw |= activate(widget);
1685 }
1686 }
1687 }
1688 }
1689 }
adamdunkelsc4902862003-04-09 00:30:45 +00001690 }
1691 }
adamdunkels19a787c2003-04-09 09:22:24 +00001692#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001693
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001694 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001695
1696 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001697
1698 screensaver_timer = 0;
1699
adamdunkelsb2486562003-04-11 20:22:03 +00001700 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001701
1702 if(dialog != NULL) {
1703 window = dialog;
1704 } else if(windows != NULL) {
1705 window = windows;
1706 } else {
1707 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001708 }
1709
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001710 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001711
1712 if(widget != NULL &&
1713 widget->type == CTK_WIDGET_TEXTENTRY &&
1714 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1715 textentry_input(c, (struct ctk_textentry *)widget);
1716 add_redrawwidget(widget);
1717#if CTK_CONF_MENUS
1718 } else if(menus.open != NULL) {
1719 redraw |= menus_input(c);
1720#endif /* CTK_CONF_MENUS */
1721 } else {
1722 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001723 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001724 switch_focus_widget(DOWN);
1725 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001726 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001727 switch_focus_widget(UP);
1728 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001729#if CTK_CONF_MENUS
1730 case CTK_CONF_MENU_KEY:
1731 if(dialog == NULL) {
1732 if(lastmenu == NULL) {
1733 menus.open = menus.menus;
1734 } else {
1735 menus.open = lastmenu;
1736 }
1737 menus.open->active = 0;
1738 redraw |= REDRAW_MENUS;
1739 }
1740 break;
1741#endif /* CTK_CONF_MENUS */
1742 case CTK_CONF_WINDOWSWITCH_KEY:
1743 if(windows != NULL) {
1744 for(window = windows; window->next != NULL;
1745 window = window->next);
1746 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001747 }
1748 break;
1749 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001750
adamdunkels3af580f2003-08-11 22:27:13 +00001751 if(c == CH_ENTER &&
1752 widget != NULL) {
1753 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001754 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001755 if(widget != NULL &&
1756 widget->type == CTK_WIDGET_TEXTENTRY) {
oliverschmidtf28743b2005-05-04 22:33:45 +00001757 if(widget->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1758 textentry_edit((struct ctk_textentry *)widget);
1759 }
adamdunkels3af580f2003-08-11 22:27:13 +00001760 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001761 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001762 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001763 /* window->focused = NULL;*/
1764 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001765 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001766 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001767 }
1768 break;
1769 }
1770 }
1771
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001772#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001773 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001774 widgetptr = redraw_widgets;
1775 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001776 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001777 *widgetptr = NULL;
1778 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001779 }
1780 redraw &= ~REDRAW_WIDGETS;
1781 redraw_widgetptr = 0;
1782 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001783#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001784 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001785#if CTK_CONF_WINDOWMOVE
1786 } else if(mode == CTK_MODE_WINDOWMOVE) {
1787
1788 redraw = 0;
1789
1790 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001791
1792#if CTK_CONF_MOUSE_SUPPORT
1793
1794 /* If the mouse has moved, we move the window as well. */
1795 if(mouse_moved) {
1796
1797 if(window->w + mxc + 2 >= width) {
1798 window->x = width - 2 - window->w;
1799 } else {
1800 window->x = mxc;
1801 }
1802
adamdunkels3b548c82004-07-04 11:41:39 +00001803 if(window->h + myc + ctk_draw_windowtitle_height +
1804 ctk_draw_windowborder_height >= height) {
1805 window->y = height - window->h -
1806 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001807 } else {
1808 window->y = myc;
1809 }
1810 if(window->y > 0) {
1811 --window->y;
1812 }
1813
1814 redraw = REDRAW_ALL;
1815 }
1816
1817 /* Check if the mouse has been clicked, and stop moving the window
1818 if so. */
1819 if(mouse_button_changed &&
1820 mouse_button == 0) {
1821 mode = CTK_MODE_NORMAL;
1822 redraw = REDRAW_ALL;
1823 }
1824#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001825
1826 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1827
1828 screensaver_timer = 0;
1829
1830 c = ctk_arch_getkey();
1831
1832 switch(c) {
1833 case CH_CURS_RIGHT:
1834 ++window->x;
1835 if(window->x + window->w + 1 >= width) {
1836 --window->x;
1837 }
1838 redraw = REDRAW_ALL;
1839 break;
1840 case CH_CURS_LEFT:
1841 if(window->x > 0) {
1842 --window->x;
1843 }
1844 redraw = REDRAW_ALL;
1845 break;
1846 case CH_CURS_DOWN:
1847 ++window->y;
1848 if(window->y + window->h + 2 >= height) {
1849 --window->y;
1850 }
1851 redraw = REDRAW_ALL;
1852 break;
1853 case CH_CURS_UP:
1854 if(window->y > 0) {
1855 --window->y;
1856 }
1857 redraw = REDRAW_ALL;
1858 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001859 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001860 mode = CTK_MODE_NORMAL;
1861 redraw = REDRAW_ALL;
1862 break;
1863 }
1864 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001865#endif /* CTK_CONF_WINDOWMOVE */
1866 }
adamdunkelsb2486562003-04-11 20:22:03 +00001867
1868 if(redraw & REDRAW_ALL) {
1869 do_redraw_all(1, height);
1870#if CTK_CONF_MENUS
1871 } else if(redraw & REDRAW_MENUPART) {
1872 do_redraw_all(1, maxnitems + 1);
1873 } else if(redraw & REDRAW_MENUS) {
1874 ctk_draw_menus(&menus);
1875#endif /* CTK_CONF_MENUS */
1876 } else if(redraw & REDRAW_FOCUS) {
1877 if(dialog != NULL) {
1878 ctk_window_redraw(dialog);
1879 } else if(windows != NULL) {
1880 ctk_window_redraw(windows);
1881 } else {
1882 ctk_window_redraw(&desktop_window);
1883 }
1884 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001885 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001886 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001887 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001888 *widgetptr = NULL;
1889 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001890 }
1891 }
1892 redraw = 0;
1893 redraw_widgetptr = 0;
1894
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001895}
1896/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001897EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1898{
1899
1900}
1901/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001902/** @} */
1903/** @} */
1904