blob: 79015368c344aeefed08b994b45ae482ffadd82a [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 *
oliverschmidtadf27db2005-03-15 15:51:17 +000046 * $Id: ctk.c,v 1.45 2005/03/15 15:51: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{
1183 static unsigned char len;
1184
1185 if(w->type == CTK_WIDGET_BUTTON) {
1186 if(w == (struct ctk_widget *)&windows->closebutton) {
1187#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001188 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001189 ctk_window_close(windows);
1190 return REDRAW_ALL;
1191#endif /* CTK_CONF_WINDOWCLOSE */
1192 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
oliverschmidte99386b2004-12-27 22:03:04 +00001193#if CTK_CONF_WINDOWMOVE
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001194 mode = CTK_MODE_WINDOWMOVE;
oliverschmidte99386b2004-12-27 22:03:04 +00001195 return REDRAW_ALL;
1196#endif /* CTK_CONF_WINDOWMOVE */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001197 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001198 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001199 }
1200#if CTK_CONF_ICONS
1201 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001202 if(w->widget.icon.owner != EK_ID_NONE) {
1203 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1204 } else {
1205 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1206 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001207#endif /* CTK_CONF_ICONS */
1208 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001209 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001210 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1211 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1212 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1213 len = strlen(w->widget.textentry.text);
1214 if(w->widget.textentry.xpos > len) {
1215 w->widget.textentry.xpos = len;
1216 }
1217 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1218 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels3b548c82004-07-04 11:41:39 +00001219 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001220 }
1221 add_redrawwidget(w);
1222 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001223 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001224 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001225 }
1226 return REDRAW_NONE;
1227}
1228/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001229static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001230textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001231 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001232{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001233 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001234 static unsigned char len, txpos, typos, tlen;
1235
1236 txpos = t->xpos;
1237 typos = t->ypos;
1238 tlen = t->len;
1239
1240 cptr = &t->text[txpos + typos * tlen];
1241
1242 switch(c) {
1243 case CH_CURS_LEFT:
1244 if(txpos > 0) {
1245 --txpos;
1246 }
1247 break;
1248
1249 case CH_CURS_RIGHT:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001250 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001251 ++txpos;
1252 }
1253 break;
1254
1255 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001256 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001257 break;
1258
1259 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001260 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001261 if(txpos == tlen) {
1262 --txpos;
1263 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001264 break;
1265
1266 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001267 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1268 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001269 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001270 break;
1271
adamdunkels9795b2e2003-08-09 23:32:37 +00001272 case CTK_CONF_WIDGETDOWN_KEY:
1273 t->state = CTK_TEXTENTRY_NORMAL;
1274 switch_focus_widget(DOWN);
1275 break;
1276 case CTK_CONF_WIDGETUP_KEY:
1277 t->state = CTK_TEXTENTRY_NORMAL;
1278 switch_focus_widget(UP);
1279 break;
1280
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001281 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001282 len = tlen - txpos;
1283 if(c == CH_DEL) {
1284 if(len == 1 && *cptr != 0) {
1285 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001286 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001287 if(txpos > 0) {
1288 --txpos;
1289 strcpy(cptr - 1, cptr);
1290 }
1291 }
1292 } else {
1293 if(ctk_arch_isprint(c)) {
1294 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001295 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001296 while(cptr2 > cptr) {
1297 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001298 --cptr2;
1299 }
adamdunkelsc9619082004-06-06 06:19:25 +00001300 ++txpos;
1301 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001302 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001303 }
1304 }
1305 break;
1306 }
1307
1308 t->xpos = txpos;
1309 t->ypos = typos;
1310}
1311/*-----------------------------------------------------------------------------------*/
1312#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001313static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001314activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001315{
1316 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001317
adamdunkelsb2486562003-04-11 20:22:03 +00001318 lastmenu = menus.open;
1319 if(menus.open == &desktopmenu) {
1320 for(w = windows; w != NULL; w = w->next) {
1321 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1322 ctk_window_open(w);
1323 menus.open = NULL;
1324 return REDRAW_ALL;
1325 }
1326 }
1327 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001328 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001329 }
1330 menus.open = NULL;
1331 return REDRAW_MENUPART;
1332}
1333/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001334static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001335menus_input(ctk_arch_key_t c)
1336{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001337
1338 if(menus.open->nitems > maxnitems) {
1339 maxnitems = menus.open->nitems;
1340 }
1341
1342
1343 switch(c) {
1344 case CH_CURS_RIGHT:
1345 switch_open_menu(1);
1346
1347 return REDRAW_MENUPART;
1348
1349 case CH_CURS_DOWN:
1350 switch_menu_item(1);
1351 return REDRAW_MENUS;
1352
1353 case CH_CURS_LEFT:
1354 switch_open_menu(0);
1355 return REDRAW_MENUPART;
1356
1357 case CH_CURS_UP:
1358 switch_menu_item(0);
1359 return REDRAW_MENUS;
1360
1361 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001362 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001363
adamdunkels88ed9c42003-03-28 12:10:09 +00001364 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365 lastmenu = menus.open;
1366 menus.open = NULL;
1367 return REDRAW_MENUPART;
1368 }
adamdunkelsb2486562003-04-11 20:22:03 +00001369
1370 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001371}
1372#endif /* CTK_CONF_MENUS */
1373/*-----------------------------------------------------------------------------------*/
1374static void
adamdunkels3b548c82004-07-04 11:41:39 +00001375handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001376{
1377 if(mode == CTK_MODE_NORMAL) {
1378 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001379 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001380#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001381 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001382#ifdef CTK_SCREENSAVER_INIT
1383 CTK_SCREENSAVER_INIT();
1384#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001385
adamdunkelscf90b0d2003-08-09 13:34:16 +00001386#endif /* CTK_CONF_SCREENSAVER */
1387 screensaver_timer = 0;
1388 }
1389 }
1390}
1391/*-----------------------------------------------------------------------------------*/
1392static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001393unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1394{
1395 if(w != NULL) {
1396 redraw |= REDRAW_WIDGETS;
1397 add_redrawwidget(w);
1398 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1399 ((struct ctk_textentry *)w)->state =
1400 CTK_TEXTENTRY_NORMAL;
1401 }
1402 w->window->focused = NULL;
1403 }
1404}
1405/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001406EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001407{
1408 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001409 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001410 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001411 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001412 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001413#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001414 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1415 mouse_clicked;
1416 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001417 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001418
adamdunkels19a787c2003-04-09 09:22:24 +00001419#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001420
1421
adamdunkels3b548c82004-07-04 11:41:39 +00001422 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001423
adamdunkels9795b2e2003-08-09 23:32:37 +00001424 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001425 timer();
1426 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001427 } */
1428 if(timer_expired(&timer)) {
1429 timer_reset(&timer);
1430 handle_timer();
1431 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001432
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001433#if CTK_CONF_MENUS
1434 if(menus.open != NULL) {
1435 maxnitems = menus.open->nitems;
1436 } else {
1437 maxnitems = 0;
1438 }
1439#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001440
1441#if CTK_CONF_MOUSE_SUPPORT
1442 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1443
1444 /* See if there is any change in the buttons. */
1445 if(ctk_mouse_button() != mouse_button) {
1446 mouse_button = ctk_mouse_button();
1447 mouse_button_changed = 1;
1448 if(mouse_button == 0) {
1449 mouse_clicked = 1;
1450 }
1451 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001452
adamdunkelsb2486562003-04-11 20:22:03 +00001453 /* Check if the mouse pointer has moved. */
1454 if(ctk_mouse_x() != mouse_x ||
1455 ctk_mouse_y() != mouse_y) {
1456 mouse_x = ctk_mouse_x();
1457 mouse_y = ctk_mouse_y();
1458 mouse_moved = 1;
1459 }
1460
1461 mxc = ctk_mouse_xtoc(mouse_x);
1462 myc = ctk_mouse_ytoc(mouse_y);
1463#endif /* CTK_CONF_MOUSE_SUPPORT */
1464
1465
adamdunkels66109622003-04-24 17:17:10 +00001466#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001467 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001468 if(ctk_arch_keyavail()
1469#if CTK_CONF_MOUSE_SUPPORT
1470 || mouse_moved || mouse_button_changed
1471#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001472 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001473 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001474 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001475 }
adamdunkels66109622003-04-24 17:17:10 +00001476 } else
1477#endif /* CTK_CONF_SCREENSAVER */
1478 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001479#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001480 /* If there is any change in the mouse conditions, find out in
1481 which window the mouse pointer currently is in order to send
1482 the correct signals, or bring a window to focus. */
1483 if(mouse_moved || mouse_button_changed) {
1484 ctk_mouse_show();
1485 screensaver_timer = 0;
1486
1487 if(myc == 0) {
1488 /* Here we should do whatever needs to be done when the mouse
1489 moves around and clicks in the menubar. */
1490 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001491 static unsigned char titlelen;
1492
adamdunkelsb2486562003-04-11 20:22:03 +00001493 /* Find out which menu that the mouse pointer is in. Start
1494 with the ->next menu after the desktop menu. We assume
1495 that the menus start one character from the left screen
1496 side and that the desktop menu is farthest to the
1497 right. */
1498 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001499 for(menu = menus.menus->next;
1500 menu != NULL; menu = menu->next) {
1501 titlelen = menu->titlelen;
1502 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001503 break;
adamdunkelse0683312003-04-09 09:02:52 +00001504 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001505 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001506 }
adamdunkelsb2486562003-04-11 20:22:03 +00001507
1508 /* Also check desktop menu. */
1509 if(mxc >= width - 7 &&
1510 mxc <= width - 1) {
1511 menu = &desktopmenu;
1512 }
1513
1514 menus.open = menu;
1515 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001516 }
adamdunkelse0683312003-04-09 09:02:52 +00001517 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001518 --myc;
1519
1520 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001521 static unsigned char nitems;
1522
adamdunkelsb2486562003-04-11 20:22:03 +00001523 /* Do whatever needs to be done when a menu is open. */
1524
adamdunkelscf90b0d2003-08-09 13:34:16 +00001525 /* First check if the mouse pointer is in the currently open
1526 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001527 if(menus.open == &desktopmenu) {
1528 menux = width - CTK_CONF_MENUWIDTH;
1529 } else {
1530 menux = 1;
1531 for(menu = menus.menus->next; menu != menus.open;
1532 menu = menu->next) {
1533 menux += menu->titlelen;
1534 }
1535 }
1536
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001537 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001538 /* Find out which of the menu items the mouse is pointing
1539 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001540 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1541 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001542 menus.open->active = myc;
1543 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001544 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001545 }
adamdunkelsb2486562003-04-11 20:22:03 +00001546 }
1547
1548 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001549 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001550 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001551 redraw |= activate_menu();
1552 } else {
1553 lastmenu = menus.open;
1554 menus.open = NULL;
1555 redraw |= REDRAW_MENUPART;
1556 }
1557 } else {
1558 redraw |= REDRAW_MENUS;
1559 }
1560 } else {
1561
adamdunkels965e2922003-06-30 20:44:57 +00001562 /* Walk through the windows from top to bottom to see in
1563 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001564 if(dialog != NULL) {
1565 window = dialog;
1566 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001567 for(window = windows; window != NULL;
1568 window = window->next) {
1569
adamdunkelsb2486562003-04-11 20:22:03 +00001570 /* Check if the mouse is within the window. */
1571 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001572 mxc <= window->x + window->w +
1573 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001574 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001575 myc <= window->y + window->h +
1576 ctk_draw_windowtitle_height +
1577 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001578 break;
1579 }
1580 }
1581 }
1582
1583
1584 /* If we didn't find any window, and there are no windows
1585 open, the mouse pointer will definately be within the
1586 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001587 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001588 window = &desktop_window;
1589 }
1590
adamdunkels965e2922003-06-30 20:44:57 +00001591 /* If the mouse pointer moves around outside of the
1592 currently focused window (or dialog), we should not have
1593 any focused widgets in the focused window so we make sure
1594 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001595 if(windows != NULL &&
1596 window != windows &&
1597 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001598 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001599 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001600 redraw |= REDRAW_WIDGETS;*/
1601 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001602 }
1603
1604 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001605 /* If the mouse was clicked outside of the current window,
1606 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001607 if(dialog == NULL &&
1608 window != &desktop_window &&
1609 window != windows &&
1610 mouse_clicked) {
1611 /* Bring window to front. */
1612 ctk_window_open(window);
1613 redraw |= REDRAW_ALL;
1614 } else {
1615
adamdunkels965e2922003-06-30 20:44:57 +00001616 /* Find out which widget currently is under the mouse
1617 pointer and give it focus, unless it already has
1618 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001619 mxc = mxc - window->x - ctk_draw_windowborder_width;
1620 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001621
adamdunkels965e2922003-06-30 20:44:57 +00001622 /* See if the mouse pointer is on a widget. If so, it
1623 should be selected and, if the button is clicked,
1624 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001625 for(widget = window->active; widget != NULL;
1626 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001627
adamdunkelsb2486562003-04-11 20:22:03 +00001628 if(mxc >= widget->x &&
1629 mxc <= widget->x + widget->w &&
1630 (myc == widget->y ||
1631 ((widget->type == CTK_WIDGET_BITMAP ||
1632 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1633 widget->type == CTK_WIDGET_ICON) &&
1634 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001635 myc <= widget->y +
1636 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001637 break;
1638 }
1639 }
1640
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001641
1642 /* if the mouse is moved in the focused window, we emit
1643 a ctk_signal_pointer_move signal to the owner of the
1644 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001645 if(mouse_moved &&
1646 (window != &desktop_window ||
1647 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001648
adamdunkels3b548c82004-07-04 11:41:39 +00001649 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001650
1651 /* If there was a focused widget that is not below the
1652 mouse pointer, we remove focus from the widget and
1653 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001654 if(window->focused != NULL &&
1655 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001656 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001657 if(CTK_WIDGET_TYPE(window->focused) ==
1658 CTK_WIDGET_TEXTENTRY) {
1659 ((struct ctk_textentry *)(window->focused))->state =
1660 CTK_TEXTENTRY_NORMAL;
1661 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001662 window->focused = NULL;*/
1663 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001664 }
1665 redraw |= REDRAW_WIDGETS;
1666 if(widget != NULL) {
1667 select_widget(widget);
1668 }
1669 }
1670
1671 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001672 ek_post(window->owner, ctk_signal_pointer_button,
1673 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001674 if(mouse_clicked && widget != NULL) {
1675 select_widget(widget);
1676 redraw |= activate(widget);
1677 }
1678 }
1679 }
1680 }
1681 }
adamdunkelsc4902862003-04-09 00:30:45 +00001682 }
1683 }
adamdunkels19a787c2003-04-09 09:22:24 +00001684#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001685
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001686 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001687
1688 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001689
1690 screensaver_timer = 0;
1691
adamdunkelsb2486562003-04-11 20:22:03 +00001692 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001693
1694 if(dialog != NULL) {
1695 window = dialog;
1696 } else if(windows != NULL) {
1697 window = windows;
1698 } else {
1699 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001700 }
1701
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001702 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001703
1704 if(widget != NULL &&
1705 widget->type == CTK_WIDGET_TEXTENTRY &&
1706 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1707 textentry_input(c, (struct ctk_textentry *)widget);
1708 add_redrawwidget(widget);
1709#if CTK_CONF_MENUS
1710 } else if(menus.open != NULL) {
1711 redraw |= menus_input(c);
1712#endif /* CTK_CONF_MENUS */
1713 } else {
1714 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001715 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001716 switch_focus_widget(DOWN);
1717 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001718 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001719 switch_focus_widget(UP);
1720 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001721#if CTK_CONF_MENUS
1722 case CTK_CONF_MENU_KEY:
1723 if(dialog == NULL) {
1724 if(lastmenu == NULL) {
1725 menus.open = menus.menus;
1726 } else {
1727 menus.open = lastmenu;
1728 }
1729 menus.open->active = 0;
1730 redraw |= REDRAW_MENUS;
1731 }
1732 break;
1733#endif /* CTK_CONF_MENUS */
1734 case CTK_CONF_WINDOWSWITCH_KEY:
1735 if(windows != NULL) {
1736 for(window = windows; window->next != NULL;
1737 window = window->next);
1738 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001739 }
1740 break;
1741 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001742
adamdunkels3af580f2003-08-11 22:27:13 +00001743 if(c == CH_ENTER &&
1744 widget != NULL) {
1745 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001746 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001747 if(widget != NULL &&
1748 widget->type == CTK_WIDGET_TEXTENTRY) {
1749 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1750 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001751 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001752 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001753 /* window->focused = NULL;*/
1754 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001755 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001756 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001757 }
1758 break;
1759 }
1760 }
1761
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001762#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001763 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001764 widgetptr = redraw_widgets;
1765 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001766 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001767 *widgetptr = NULL;
1768 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001769 }
1770 redraw &= ~REDRAW_WIDGETS;
1771 redraw_widgetptr = 0;
1772 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001773#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001774 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001775#if CTK_CONF_WINDOWMOVE
1776 } else if(mode == CTK_MODE_WINDOWMOVE) {
1777
1778 redraw = 0;
1779
1780 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001781
1782#if CTK_CONF_MOUSE_SUPPORT
1783
1784 /* If the mouse has moved, we move the window as well. */
1785 if(mouse_moved) {
1786
1787 if(window->w + mxc + 2 >= width) {
1788 window->x = width - 2 - window->w;
1789 } else {
1790 window->x = mxc;
1791 }
1792
adamdunkels3b548c82004-07-04 11:41:39 +00001793 if(window->h + myc + ctk_draw_windowtitle_height +
1794 ctk_draw_windowborder_height >= height) {
1795 window->y = height - window->h -
1796 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001797 } else {
1798 window->y = myc;
1799 }
1800 if(window->y > 0) {
1801 --window->y;
1802 }
1803
1804 redraw = REDRAW_ALL;
1805 }
1806
1807 /* Check if the mouse has been clicked, and stop moving the window
1808 if so. */
1809 if(mouse_button_changed &&
1810 mouse_button == 0) {
1811 mode = CTK_MODE_NORMAL;
1812 redraw = REDRAW_ALL;
1813 }
1814#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001815
1816 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1817
1818 screensaver_timer = 0;
1819
1820 c = ctk_arch_getkey();
1821
1822 switch(c) {
1823 case CH_CURS_RIGHT:
1824 ++window->x;
1825 if(window->x + window->w + 1 >= width) {
1826 --window->x;
1827 }
1828 redraw = REDRAW_ALL;
1829 break;
1830 case CH_CURS_LEFT:
1831 if(window->x > 0) {
1832 --window->x;
1833 }
1834 redraw = REDRAW_ALL;
1835 break;
1836 case CH_CURS_DOWN:
1837 ++window->y;
1838 if(window->y + window->h + 2 >= height) {
1839 --window->y;
1840 }
1841 redraw = REDRAW_ALL;
1842 break;
1843 case CH_CURS_UP:
1844 if(window->y > 0) {
1845 --window->y;
1846 }
1847 redraw = REDRAW_ALL;
1848 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001849 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001850 mode = CTK_MODE_NORMAL;
1851 redraw = REDRAW_ALL;
1852 break;
1853 }
1854 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001855#endif /* CTK_CONF_WINDOWMOVE */
1856 }
adamdunkelsb2486562003-04-11 20:22:03 +00001857
1858 if(redraw & REDRAW_ALL) {
1859 do_redraw_all(1, height);
1860#if CTK_CONF_MENUS
1861 } else if(redraw & REDRAW_MENUPART) {
1862 do_redraw_all(1, maxnitems + 1);
1863 } else if(redraw & REDRAW_MENUS) {
1864 ctk_draw_menus(&menus);
1865#endif /* CTK_CONF_MENUS */
1866 } else if(redraw & REDRAW_FOCUS) {
1867 if(dialog != NULL) {
1868 ctk_window_redraw(dialog);
1869 } else if(windows != NULL) {
1870 ctk_window_redraw(windows);
1871 } else {
1872 ctk_window_redraw(&desktop_window);
1873 }
1874 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001875 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001876 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001877 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001878 *widgetptr = NULL;
1879 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001880 }
1881 }
1882 redraw = 0;
1883 redraw_widgetptr = 0;
1884
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001885}
1886/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001887EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1888{
1889
1890}
1891/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001892/** @} */
1893/** @} */
1894