blob: 31c916030acd26efe8ee5f563d6a93644a491f6b [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 *
oliverschmidt0096f6a2005-05-04 21:50:17 +000046 * $Id: ctk.c,v 1.47 2005/05/04 21:50:17 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/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001180static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001181activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001182{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001183 if(w->type == CTK_WIDGET_BUTTON) {
1184 if(w == (struct ctk_widget *)&windows->closebutton) {
1185#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001186 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001187 ctk_window_close(windows);
1188 return REDRAW_ALL;
1189#endif /* CTK_CONF_WINDOWCLOSE */
1190 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
oliverschmidte99386b2004-12-27 22:03:04 +00001191#if CTK_CONF_WINDOWMOVE
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001192 mode = CTK_MODE_WINDOWMOVE;
oliverschmidte99386b2004-12-27 22:03:04 +00001193 return REDRAW_ALL;
1194#endif /* CTK_CONF_WINDOWMOVE */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001195 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001196 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001197 }
1198#if CTK_CONF_ICONS
1199 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001200 if(w->widget.icon.owner != EK_ID_NONE) {
1201 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1202 } else {
1203 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1204 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001205#endif /* CTK_CONF_ICONS */
1206 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001207 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001208 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1209 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1210 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
oliverschmidtb590c102005-04-24 23:01:20 +00001211 w->widget.textentry.xpos = strlen(w->widget.textentry.text);
1212 if(w->widget.textentry.xpos == w->widget.textentry.len) {
1213 --w->widget.textentry.xpos;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001214 }
1215 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1216 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001217 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 }
1219 add_redrawwidget(w);
1220 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001221 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001222 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001223 }
1224 return REDRAW_NONE;
1225}
1226/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001227static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001228textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001229 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001230{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001231 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001232 static unsigned char len, txpos, typos, tlen;
1233
oliverschmidt0096f6a2005-05-04 21:50:17 +00001234 if(t->input != NULL && t->input(c, t)) {
1235 return;
1236 }
1237
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001238 txpos = t->xpos;
1239 typos = t->ypos;
1240 tlen = t->len;
1241
1242 cptr = &t->text[txpos + typos * tlen];
1243
1244 switch(c) {
1245 case CH_CURS_LEFT:
1246 if(txpos > 0) {
1247 --txpos;
1248 }
1249 break;
1250
1251 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001252 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001253 ++txpos;
1254 }
1255 break;
1256
1257 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001258 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001259 break;
1260
1261 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001262 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001263 if(txpos == tlen) {
1264 --txpos;
1265 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266 break;
1267
1268 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001269 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1270 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001271 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272 break;
1273
adamdunkels9795b2e2003-08-09 23:32:37 +00001274 case CTK_CONF_WIDGETDOWN_KEY:
1275 t->state = CTK_TEXTENTRY_NORMAL;
1276 switch_focus_widget(DOWN);
1277 break;
1278 case CTK_CONF_WIDGETUP_KEY:
1279 t->state = CTK_TEXTENTRY_NORMAL;
1280 switch_focus_widget(UP);
1281 break;
1282
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001283 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001284 len = tlen - txpos;
1285 if(c == CH_DEL) {
1286 if(len == 1 && *cptr != 0) {
1287 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001288 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001289 if(txpos > 0) {
1290 --txpos;
1291 strcpy(cptr - 1, cptr);
1292 }
1293 }
1294 } else {
1295 if(ctk_arch_isprint(c)) {
1296 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001297 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001298 while(cptr2 > cptr) {
1299 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001300 --cptr2;
1301 }
adamdunkelsc9619082004-06-06 06:19:25 +00001302 ++txpos;
1303 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001304 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001305 }
1306 }
1307 break;
1308 }
1309
1310 t->xpos = txpos;
1311 t->ypos = typos;
1312}
1313/*-----------------------------------------------------------------------------------*/
1314#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001315static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001316activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001317{
1318 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001319
adamdunkelsb2486562003-04-11 20:22:03 +00001320 lastmenu = menus.open;
1321 if(menus.open == &desktopmenu) {
1322 for(w = windows; w != NULL; w = w->next) {
1323 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1324 ctk_window_open(w);
1325 menus.open = NULL;
1326 return REDRAW_ALL;
1327 }
1328 }
1329 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001330 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001331 }
1332 menus.open = NULL;
1333 return REDRAW_MENUPART;
1334}
1335/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001336static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001337menus_input(ctk_arch_key_t c)
1338{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001339
1340 if(menus.open->nitems > maxnitems) {
1341 maxnitems = menus.open->nitems;
1342 }
1343
1344
1345 switch(c) {
1346 case CH_CURS_RIGHT:
1347 switch_open_menu(1);
1348
1349 return REDRAW_MENUPART;
1350
1351 case CH_CURS_DOWN:
1352 switch_menu_item(1);
1353 return REDRAW_MENUS;
1354
1355 case CH_CURS_LEFT:
1356 switch_open_menu(0);
1357 return REDRAW_MENUPART;
1358
1359 case CH_CURS_UP:
1360 switch_menu_item(0);
1361 return REDRAW_MENUS;
1362
1363 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001364 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365
adamdunkels88ed9c42003-03-28 12:10:09 +00001366 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001367 lastmenu = menus.open;
1368 menus.open = NULL;
1369 return REDRAW_MENUPART;
1370 }
adamdunkelsb2486562003-04-11 20:22:03 +00001371
1372 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001373}
1374#endif /* CTK_CONF_MENUS */
1375/*-----------------------------------------------------------------------------------*/
1376static void
adamdunkels3b548c82004-07-04 11:41:39 +00001377handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001378{
1379 if(mode == CTK_MODE_NORMAL) {
1380 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001381 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001382#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001383 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001384#ifdef CTK_SCREENSAVER_INIT
1385 CTK_SCREENSAVER_INIT();
1386#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001387
adamdunkelscf90b0d2003-08-09 13:34:16 +00001388#endif /* CTK_CONF_SCREENSAVER */
1389 screensaver_timer = 0;
1390 }
1391 }
1392}
1393/*-----------------------------------------------------------------------------------*/
1394static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001395unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1396{
1397 if(w != NULL) {
1398 redraw |= REDRAW_WIDGETS;
1399 add_redrawwidget(w);
1400 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1401 ((struct ctk_textentry *)w)->state =
1402 CTK_TEXTENTRY_NORMAL;
1403 }
1404 w->window->focused = NULL;
1405 }
1406}
1407/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001408EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001409{
1410 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001411 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001412 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001413 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001414 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001415#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001416 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1417 mouse_clicked;
1418 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001419 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001420
adamdunkels19a787c2003-04-09 09:22:24 +00001421#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001422
1423
adamdunkels3b548c82004-07-04 11:41:39 +00001424 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001425
adamdunkels9795b2e2003-08-09 23:32:37 +00001426 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001427 timer();
1428 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001429 } */
1430 if(timer_expired(&timer)) {
1431 timer_reset(&timer);
1432 handle_timer();
1433 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001434
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001435#if CTK_CONF_MENUS
1436 if(menus.open != NULL) {
1437 maxnitems = menus.open->nitems;
1438 } else {
1439 maxnitems = 0;
1440 }
1441#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001442
1443#if CTK_CONF_MOUSE_SUPPORT
1444 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1445
1446 /* See if there is any change in the buttons. */
1447 if(ctk_mouse_button() != mouse_button) {
1448 mouse_button = ctk_mouse_button();
1449 mouse_button_changed = 1;
1450 if(mouse_button == 0) {
1451 mouse_clicked = 1;
1452 }
1453 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001454
adamdunkelsb2486562003-04-11 20:22:03 +00001455 /* Check if the mouse pointer has moved. */
1456 if(ctk_mouse_x() != mouse_x ||
1457 ctk_mouse_y() != mouse_y) {
1458 mouse_x = ctk_mouse_x();
1459 mouse_y = ctk_mouse_y();
1460 mouse_moved = 1;
1461 }
1462
1463 mxc = ctk_mouse_xtoc(mouse_x);
1464 myc = ctk_mouse_ytoc(mouse_y);
1465#endif /* CTK_CONF_MOUSE_SUPPORT */
1466
1467
adamdunkels66109622003-04-24 17:17:10 +00001468#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001469 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001470 if(ctk_arch_keyavail()
1471#if CTK_CONF_MOUSE_SUPPORT
1472 || mouse_moved || mouse_button_changed
1473#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001474 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001475 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001476 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001477 }
adamdunkels66109622003-04-24 17:17:10 +00001478 } else
1479#endif /* CTK_CONF_SCREENSAVER */
1480 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001481#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001482 /* If there is any change in the mouse conditions, find out in
1483 which window the mouse pointer currently is in order to send
1484 the correct signals, or bring a window to focus. */
1485 if(mouse_moved || mouse_button_changed) {
1486 ctk_mouse_show();
1487 screensaver_timer = 0;
1488
1489 if(myc == 0) {
1490 /* Here we should do whatever needs to be done when the mouse
1491 moves around and clicks in the menubar. */
1492 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001493 static unsigned char titlelen;
1494
adamdunkelsb2486562003-04-11 20:22:03 +00001495 /* Find out which menu that the mouse pointer is in. Start
1496 with the ->next menu after the desktop menu. We assume
1497 that the menus start one character from the left screen
1498 side and that the desktop menu is farthest to the
1499 right. */
1500 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001501 for(menu = menus.menus->next;
1502 menu != NULL; menu = menu->next) {
1503 titlelen = menu->titlelen;
1504 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001505 break;
adamdunkelse0683312003-04-09 09:02:52 +00001506 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001507 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001508 }
adamdunkelsb2486562003-04-11 20:22:03 +00001509
1510 /* Also check desktop menu. */
1511 if(mxc >= width - 7 &&
1512 mxc <= width - 1) {
1513 menu = &desktopmenu;
1514 }
1515
1516 menus.open = menu;
1517 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001518 }
adamdunkelse0683312003-04-09 09:02:52 +00001519 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001520 --myc;
1521
1522 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001523 static unsigned char nitems;
1524
adamdunkelsb2486562003-04-11 20:22:03 +00001525 /* Do whatever needs to be done when a menu is open. */
1526
adamdunkelscf90b0d2003-08-09 13:34:16 +00001527 /* First check if the mouse pointer is in the currently open
1528 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001529 if(menus.open == &desktopmenu) {
1530 menux = width - CTK_CONF_MENUWIDTH;
1531 } else {
1532 menux = 1;
1533 for(menu = menus.menus->next; menu != menus.open;
1534 menu = menu->next) {
1535 menux += menu->titlelen;
1536 }
1537 }
1538
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001539 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001540 /* Find out which of the menu items the mouse is pointing
1541 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001542 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1543 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001544 menus.open->active = myc;
1545 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001546 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001547 }
adamdunkelsb2486562003-04-11 20:22:03 +00001548 }
1549
1550 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001551 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001553 redraw |= activate_menu();
1554 } else {
1555 lastmenu = menus.open;
1556 menus.open = NULL;
1557 redraw |= REDRAW_MENUPART;
1558 }
1559 } else {
1560 redraw |= REDRAW_MENUS;
1561 }
1562 } else {
1563
adamdunkels965e2922003-06-30 20:44:57 +00001564 /* Walk through the windows from top to bottom to see in
1565 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001566 if(dialog != NULL) {
1567 window = dialog;
1568 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001569 for(window = windows; window != NULL;
1570 window = window->next) {
1571
adamdunkelsb2486562003-04-11 20:22:03 +00001572 /* Check if the mouse is within the window. */
1573 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001574 mxc <= window->x + window->w +
1575 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001576 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001577 myc <= window->y + window->h +
1578 ctk_draw_windowtitle_height +
1579 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001580 break;
1581 }
1582 }
1583 }
1584
1585
1586 /* If we didn't find any window, and there are no windows
1587 open, the mouse pointer will definately be within the
1588 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001589 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001590 window = &desktop_window;
1591 }
1592
adamdunkels965e2922003-06-30 20:44:57 +00001593 /* If the mouse pointer moves around outside of the
1594 currently focused window (or dialog), we should not have
1595 any focused widgets in the focused window so we make sure
1596 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001597 if(windows != NULL &&
1598 window != windows &&
1599 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001600 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001601 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001602 redraw |= REDRAW_WIDGETS;*/
1603 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001604 }
1605
1606 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001607 /* If the mouse was clicked outside of the current window,
1608 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001609 if(dialog == NULL &&
1610 window != &desktop_window &&
1611 window != windows &&
1612 mouse_clicked) {
1613 /* Bring window to front. */
1614 ctk_window_open(window);
1615 redraw |= REDRAW_ALL;
1616 } else {
1617
adamdunkels965e2922003-06-30 20:44:57 +00001618 /* Find out which widget currently is under the mouse
1619 pointer and give it focus, unless it already has
1620 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001621 mxc = mxc - window->x - ctk_draw_windowborder_width;
1622 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001623
adamdunkels965e2922003-06-30 20:44:57 +00001624 /* See if the mouse pointer is on a widget. If so, it
1625 should be selected and, if the button is clicked,
1626 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001627 for(widget = window->active; widget != NULL;
1628 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001629
adamdunkelsb2486562003-04-11 20:22:03 +00001630 if(mxc >= widget->x &&
1631 mxc <= widget->x + widget->w &&
1632 (myc == widget->y ||
1633 ((widget->type == CTK_WIDGET_BITMAP ||
1634 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1635 widget->type == CTK_WIDGET_ICON) &&
1636 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001637 myc <= widget->y +
1638 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001639 break;
1640 }
1641 }
1642
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001643
1644 /* if the mouse is moved in the focused window, we emit
1645 a ctk_signal_pointer_move signal to the owner of the
1646 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001647 if(mouse_moved &&
1648 (window != &desktop_window ||
1649 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001650
adamdunkels3b548c82004-07-04 11:41:39 +00001651 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001652
1653 /* If there was a focused widget that is not below the
1654 mouse pointer, we remove focus from the widget and
1655 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001656 if(window->focused != NULL &&
1657 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001658 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001659 if(CTK_WIDGET_TYPE(window->focused) ==
1660 CTK_WIDGET_TEXTENTRY) {
1661 ((struct ctk_textentry *)(window->focused))->state =
1662 CTK_TEXTENTRY_NORMAL;
1663 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001664 window->focused = NULL;*/
1665 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001666 }
1667 redraw |= REDRAW_WIDGETS;
1668 if(widget != NULL) {
1669 select_widget(widget);
1670 }
1671 }
1672
1673 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001674 ek_post(window->owner, ctk_signal_pointer_button,
1675 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001676 if(mouse_clicked && widget != NULL) {
1677 select_widget(widget);
1678 redraw |= activate(widget);
1679 }
1680 }
1681 }
1682 }
1683 }
adamdunkelsc4902862003-04-09 00:30:45 +00001684 }
1685 }
adamdunkels19a787c2003-04-09 09:22:24 +00001686#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001687
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001688 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001689
1690 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001691
1692 screensaver_timer = 0;
1693
adamdunkelsb2486562003-04-11 20:22:03 +00001694 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001695
1696 if(dialog != NULL) {
1697 window = dialog;
1698 } else if(windows != NULL) {
1699 window = windows;
1700 } else {
1701 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001702 }
1703
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001704 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001705
1706 if(widget != NULL &&
1707 widget->type == CTK_WIDGET_TEXTENTRY &&
1708 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1709 textentry_input(c, (struct ctk_textentry *)widget);
1710 add_redrawwidget(widget);
1711#if CTK_CONF_MENUS
1712 } else if(menus.open != NULL) {
1713 redraw |= menus_input(c);
1714#endif /* CTK_CONF_MENUS */
1715 } else {
1716 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001717 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001718 switch_focus_widget(DOWN);
1719 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001720 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001721 switch_focus_widget(UP);
1722 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001723#if CTK_CONF_MENUS
1724 case CTK_CONF_MENU_KEY:
1725 if(dialog == NULL) {
1726 if(lastmenu == NULL) {
1727 menus.open = menus.menus;
1728 } else {
1729 menus.open = lastmenu;
1730 }
1731 menus.open->active = 0;
1732 redraw |= REDRAW_MENUS;
1733 }
1734 break;
1735#endif /* CTK_CONF_MENUS */
1736 case CTK_CONF_WINDOWSWITCH_KEY:
1737 if(windows != NULL) {
1738 for(window = windows; window->next != NULL;
1739 window = window->next);
1740 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001741 }
1742 break;
1743 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001744
adamdunkels3af580f2003-08-11 22:27:13 +00001745 if(c == CH_ENTER &&
1746 widget != NULL) {
1747 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001748 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001749 if(widget != NULL &&
1750 widget->type == CTK_WIDGET_TEXTENTRY) {
1751 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1752 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001753 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001754 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001755 /* window->focused = NULL;*/
1756 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001757 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001758 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001759 }
1760 break;
1761 }
1762 }
1763
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001764#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001765 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001766 widgetptr = redraw_widgets;
1767 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001768 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001769 *widgetptr = NULL;
1770 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001771 }
1772 redraw &= ~REDRAW_WIDGETS;
1773 redraw_widgetptr = 0;
1774 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001775#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001776 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001777#if CTK_CONF_WINDOWMOVE
1778 } else if(mode == CTK_MODE_WINDOWMOVE) {
1779
1780 redraw = 0;
1781
1782 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001783
1784#if CTK_CONF_MOUSE_SUPPORT
1785
1786 /* If the mouse has moved, we move the window as well. */
1787 if(mouse_moved) {
1788
1789 if(window->w + mxc + 2 >= width) {
1790 window->x = width - 2 - window->w;
1791 } else {
1792 window->x = mxc;
1793 }
1794
adamdunkels3b548c82004-07-04 11:41:39 +00001795 if(window->h + myc + ctk_draw_windowtitle_height +
1796 ctk_draw_windowborder_height >= height) {
1797 window->y = height - window->h -
1798 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001799 } else {
1800 window->y = myc;
1801 }
1802 if(window->y > 0) {
1803 --window->y;
1804 }
1805
1806 redraw = REDRAW_ALL;
1807 }
1808
1809 /* Check if the mouse has been clicked, and stop moving the window
1810 if so. */
1811 if(mouse_button_changed &&
1812 mouse_button == 0) {
1813 mode = CTK_MODE_NORMAL;
1814 redraw = REDRAW_ALL;
1815 }
1816#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001817
1818 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1819
1820 screensaver_timer = 0;
1821
1822 c = ctk_arch_getkey();
1823
1824 switch(c) {
1825 case CH_CURS_RIGHT:
1826 ++window->x;
1827 if(window->x + window->w + 1 >= width) {
1828 --window->x;
1829 }
1830 redraw = REDRAW_ALL;
1831 break;
1832 case CH_CURS_LEFT:
1833 if(window->x > 0) {
1834 --window->x;
1835 }
1836 redraw = REDRAW_ALL;
1837 break;
1838 case CH_CURS_DOWN:
1839 ++window->y;
1840 if(window->y + window->h + 2 >= height) {
1841 --window->y;
1842 }
1843 redraw = REDRAW_ALL;
1844 break;
1845 case CH_CURS_UP:
1846 if(window->y > 0) {
1847 --window->y;
1848 }
1849 redraw = REDRAW_ALL;
1850 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001851 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001852 mode = CTK_MODE_NORMAL;
1853 redraw = REDRAW_ALL;
1854 break;
1855 }
1856 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001857#endif /* CTK_CONF_WINDOWMOVE */
1858 }
adamdunkelsb2486562003-04-11 20:22:03 +00001859
1860 if(redraw & REDRAW_ALL) {
1861 do_redraw_all(1, height);
1862#if CTK_CONF_MENUS
1863 } else if(redraw & REDRAW_MENUPART) {
1864 do_redraw_all(1, maxnitems + 1);
1865 } else if(redraw & REDRAW_MENUS) {
1866 ctk_draw_menus(&menus);
1867#endif /* CTK_CONF_MENUS */
1868 } else if(redraw & REDRAW_FOCUS) {
1869 if(dialog != NULL) {
1870 ctk_window_redraw(dialog);
1871 } else if(windows != NULL) {
1872 ctk_window_redraw(windows);
1873 } else {
1874 ctk_window_redraw(&desktop_window);
1875 }
1876 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001877 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001878 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001879 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001880 *widgetptr = NULL;
1881 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001882 }
1883 }
1884 redraw = 0;
1885 redraw_widgetptr = 0;
1886
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001887}
1888/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001889EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1890{
1891
1892}
1893/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001894/** @} */
1895/** @} */
1896