blob: b54e8239d3d65d871b853c464ab13a6a699942a8 [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 *
oliverschmidtcd6c30b2005-05-05 20:54:16 +000046 * $Id: ctk.c,v 1.50 2005/05/05 20:54:16 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
oliverschmidt11511242005-05-04 23:05:37 +0000190static void CC_FASTCALL
191textentry_input(ctk_arch_key_t c,
192 CC_REGISTER_ARG struct ctk_textentry *t);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000193#if CTK_CONF_MENUS
194/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000195/**
196 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000197 *
198 * Creates the leftmost menu, "Desktop". Since the desktop menu
199 * contains the list of all open windows, this function will be called
200 * whenever a window is opened or closed.
201 */
adamdunkels35298692003-08-31 22:16:49 +0000202/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000203static void
204make_desktopmenu(void)
205{
206 struct ctk_window *w;
207
208 desktopmenu.nitems = 0;
209
210 if(windows == NULL) {
211 ctk_menuitem_add(&desktopmenu, "(No windows)");
212 } else {
213 for(w = windows; w != NULL; w = w->next) {
214 ctk_menuitem_add(&desktopmenu, w->title);
215 }
216 }
217}
218#endif /* CTK_CONF_MENUS */
219/*-----------------------------------------------------------------------------------*/
adamdunkels125483e2004-08-09 20:29:35 +0000220static void
221arrange_icons(void)
222{
223 struct ctk_widget *icon;
224
225 iconx = ICONX_START;
226 icony = ICONY_START;
227
228 for(icon = desktop_window.active; icon != NULL; icon = icon->next) {
229
230 icon->x = iconx;
231 icon->y = icony;
232
233 icony += ICONY_DELTA;
234 if(icony >= ICONY_MAX ||
235 icony < ICONY_MIN) {
236 icony = ICONY_START;
237 iconx += ICONX_DELTA;
238 }
239 }
240}
241/*-----------------------------------------------------------------------------------*/
242void
243ctk_restore(void)
244{
245 ctk_draw_init();
246
247 height = ctk_draw_height();
248 width = ctk_draw_width();
249
250 arrange_icons();
251
252 redraw = REDRAW_ALL;
253}
254/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000255/**
256 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000257 *
adamdunkels35298692003-08-31 22:16:49 +0000258 * This function must be called before any other CTK function, but
259 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000260 */
adamdunkels35298692003-08-31 22:16:49 +0000261/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000262void
263ctk_init(void)
264{
adamdunkels3b548c82004-07-04 11:41:39 +0000265 ctkid = ek_start(&p);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000266
267 windows = NULL;
268 dialog = NULL;
269
270#if CTK_CONF_MENUS
271 ctk_menu_new(&desktopmenu, "Desktop");
272 make_desktopmenu();
273 menus.menus = menus.desktopmenu = &desktopmenu;
274#endif /* CTK_CONF_MENUS */
275
adamdunkelsb2486562003-04-11 20:22:03 +0000276#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000277 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000278 ctk_mouse_show();
279#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000280
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000281 ctk_draw_init();
282
283 height = ctk_draw_height();
284 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000285
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000286 desktop_window.active = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000287 desktop_window.owner = ctkid;
adamdunkelsb2486562003-04-11 20:22:03 +0000288
adamdunkels3b548c82004-07-04 11:41:39 +0000289 ctk_signal_keypress = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000290
291 ctk_signal_button_activate =
adamdunkels3b548c82004-07-04 11:41:39 +0000292 ctk_signal_widget_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000293
294 ctk_signal_button_hover =
295 ctk_signal_hyperlink_hover =
adamdunkels3b548c82004-07-04 11:41:39 +0000296 ctk_signal_widget_select = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000297
adamdunkels3b548c82004-07-04 11:41:39 +0000298 ctk_signal_hyperlink_activate = ek_alloc_event();
adamdunkels58917a82003-04-18 00:18:38 +0000299
adamdunkels3b548c82004-07-04 11:41:39 +0000300 ctk_signal_menu_activate = ek_alloc_event();
301 ctk_signal_window_close = ek_alloc_event();
adamdunkelsc4902862003-04-09 00:30:45 +0000302
adamdunkels3b548c82004-07-04 11:41:39 +0000303 ctk_signal_pointer_move = ek_alloc_event();
304 ctk_signal_pointer_button = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000305
306
307#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +0000308 ctk_signal_screensaver_start = ek_alloc_event();
309 ctk_signal_screensaver_stop = ek_alloc_event();
adamdunkels66109622003-04-24 17:17:10 +0000310#endif /* CTK_CONF_SCREENSAVER */
311
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000312
313 mode = CTK_MODE_NORMAL;
314
315 iconx = ICONX_START;
316 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000317
318 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000319
adamdunkels3b548c82004-07-04 11:41:39 +0000320 /* start = ek_clock();*/
321 timer_set(&timer, CLOCK_SECOND);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322}
adamdunkelse937ded2003-10-01 07:53:57 +0000323
324/**
325 * \addtogroup ctkappfunc
326 * @{
327 */
328
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000329/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000330/**
331 * Sets the current CTK mode.
332 *
333 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
334 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
335 * keypresses and mouse pointer movements are processed and the screen
336 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
337 * performed and the first key press or pointer movement will cause
338 * the ctk_signal_screensaver_stop to be emitted. In the
339 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
340 * ignored and no screen redraws are made.
341 *
342 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000343 */
adamdunkels35298692003-08-31 22:16:49 +0000344/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000345void
346ctk_mode_set(unsigned char m) {
347 mode = m;
348}
349/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000350/**
351 * Retrieves the current CTK mode.
352 *
353 * \return The current CTK mode.
354 */
355/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000356unsigned char
357ctk_mode_get(void) {
358 return mode;
359}
360/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000361/**
362 * Add an icon to the desktop.
363 *
364 * \param icon The icon to be added.
adamdunkels0404ef12003-09-04 19:36:04 +0000365 *
366 * \param id The process ID of the process that owns the icon.
adamdunkels35298692003-08-31 22:16:49 +0000367 */
368/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000369void
adamdunkels0404ef12003-09-04 19:36:04 +0000370ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, ek_id_t id)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000371{
adamdunkels0404ef12003-09-04 19:36:04 +0000372#if CTK_CONF_ICONS
adamdunkels125483e2004-08-09 20:29:35 +0000373 /* icon->x = iconx;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000374 icon->y = icony;
adamdunkels0404ef12003-09-04 19:36:04 +0000375 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000376
377 icony += ICONY_DELTA;
378 if(icony >= ICONY_MAX) {
379 icony = ICONY_START;
380 iconx += ICONX_DELTA;
adamdunkels125483e2004-08-09 20:29:35 +0000381 }*/
382 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000383 ctk_widget_add(&desktop_window, icon);
adamdunkels125483e2004-08-09 20:29:35 +0000384 arrange_icons();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000385#endif /* CTK_CONF_ICONS */
386}
387/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000388/**
389 * Open a dialog box.
390 *
391 * \param d The dialog to be opened.
392 */
393/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000394void
395ctk_dialog_open(struct ctk_window *d)
396{
397 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000398 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000399}
400/*-----------------------------------------------------------------------------------*/
401/**
402 * Close the dialog box, if one is open.
403 *
404 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000405/*-----------------------------------------------------------------------------------*/
406void
407ctk_dialog_close(void)
408{
409 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000410 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000411}
412/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000413/**
414 * Open a window, or bring window to front if already open.
415 *
416 * \param w The window to be opened.
417 */
418/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000419void
adamdunkelsd07a5422003-04-05 12:22:35 +0000420ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000421{
422 struct ctk_window *w2;
423
424 /* Check if already open. */
425 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
426 if(w2 == NULL) {
427 /* Not open, so we add it at the head of the list of open
428 windows. */
429 w->next = windows;
430 if(windows != NULL) {
431 windows->prev = w;
432 }
433 windows = w;
434 w->prev = NULL;
435 } else {
436 /* Window already open, so we move it to the front of the windows
437 list. */
438 if(w != windows) {
439 if(w->next != NULL) {
440 w->next->prev = w->prev;
441 }
442 if(w->prev != NULL) {
443 w->prev->next = w->next;
444 }
445 w->next = windows;
446 windows->prev = w;
447 windows = w;
448 w->prev = NULL;
449 }
450 }
451
452#if CTK_CONF_MENUS
453 /* Recreate the Desktop menu's window entries.*/
454 make_desktopmenu();
455#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000456
457 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458}
459/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000460/**
461 * Close a window if it is open.
462 *
463 * If the window is not open, this function does nothing.
464 *
465 * \param w The window to be closed.
466 */
467/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000468void
469ctk_window_close(struct ctk_window *w)
470{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000471 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000472
473 if(w == NULL) {
474 return;
475 }
476
477 /* Check if the window to be closed is the first window on the
478 list. */
479 if(w == windows) {
480 windows = w->next;
481 if(windows != NULL) {
482 windows->prev = NULL;
483 }
484 w->next = w->prev = NULL;
485 } else {
486 /* Otherwise we step through the list until we find the window
487 before the one to be closed. We then redirect its ->next
488 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000489 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
490
491 if(w2 == NULL) {
492 /* The window wasn't open, so there is nothing more for us to
493 do. */
494 return;
495 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000496
497 if(w->next != NULL) {
498 w->next->prev = w->prev;
499 }
500 w2->next = w->next;
501
502 w->next = w->prev = NULL;
503 }
504
505#if CTK_CONF_MENUS
506 /* Recreate the Desktop menu's window entries.*/
507 make_desktopmenu();
508#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000509 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000510}
511/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000512/**
513 * \internal Create the move and close buttons on the window titlebar.
514 */
515/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000516static void
517make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000518{
adamdunkels3b548c82004-07-04 11:41:39 +0000519 unsigned char placement;
520
521 if(ctk_draw_windowtitle_height >= 2) {
522 placement = -1 - ctk_draw_windowtitle_height/2;
523 } else {
524 placement = -1;
525 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526#if CTK_CONF_WINDOWMOVE
adamdunkels3b548c82004-07-04 11:41:39 +0000527 CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
528 window->titlelen, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529#else
adamdunkels3b548c82004-07-04 11:41:39 +0000530 CTK_LABEL_NEW(&window->titlebutton, 0, placement,
531 window->titlelen, 1, window->title);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000532#endif /* CTK_CONF_WINDOWMOVE */
533 CTK_WIDGET_ADD(window, &window->titlebutton);
534
535
536#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +0000537 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, placement,
538 1, "x");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000539#else
adamdunkels3b548c82004-07-04 11:41:39 +0000540 CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
541 3, 1, " ");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000542#endif /* CTK_CONF_WINDOWCLOSE */
543 CTK_WIDGET_ADD(window, &window->closebutton);
544}
545/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000546/**
547 * Remove all widgets from a window.
548 *
549 * \param w The window to be cleared.
550 */
551/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000552void
adamdunkels35298692003-08-31 22:16:49 +0000553ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000554{
adamdunkels35298692003-08-31 22:16:49 +0000555 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000556
adamdunkels35298692003-08-31 22:16:49 +0000557 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000558}
559/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000560/**
561 * Add a menu to the menu bar.
562 *
563 * \param menu The menu to be added.
564 *
565 * \note Do not call this function multiple times for the same menu,
566 * as no check is made to see if the menu already is in the menu bar.
567 */
568/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000569void
570ctk_menu_add(struct ctk_menu *menu)
571{
572#if CTK_CONF_MENUS
573 struct ctk_menu *m;
574
575 if(lastmenu == NULL) {
576 lastmenu = menu;
577 }
578
579 for(m = menus.menus; m->next != NULL; m = m->next) {
580 if(m == menu) {
581 return;
582 }
583 }
584 m->next = menu;
585 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000586
587 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000588#endif /* CTK_CONF_MENUS */
589}
590/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000591/**
592 * Remove a menu from the menu bar.
593 *
594 * \param menu The menu to be removed.
595 */
596/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000597void
598ctk_menu_remove(struct ctk_menu *menu)
599{
600#if CTK_CONF_MENUS
601 struct ctk_menu *m;
602
603 for(m = menus.menus; m->next != NULL; m = m->next) {
604 if(m->next == menu) {
605 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000606 if(menu == lastmenu) {
607 lastmenu = NULL;
608 }
609 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000610 return;
611 }
612 }
613#endif /* CTK_CONF_MENUS */
614}
615/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000616/**
617 * \internal Redraws everything on the screen within the clip
618 * interval.
619 *
620 * \param clipy1 The upper bound of the clip interval
621 * \param clipy2 The lower bound of the clip interval
622 */
623/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000624static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000625do_redraw_all(unsigned char clipy1, unsigned char clipy2)
626{
627 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000628 static struct ctk_widget *widget;
oliverschmidte99386b2004-12-27 22:03:04 +0000629 unsigned char focus;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000630
631 if(mode != CTK_MODE_NORMAL &&
632 mode != CTK_MODE_WINDOWMOVE) {
633 return;
634 }
635
636 ctk_draw_clear(clipy1, clipy2);
637
638 /* Draw widgets in root window */
639 for(widget = desktop_window.active;
640 widget != NULL; widget = widget->next) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000641 ctk_draw_widget(widget, windows != NULL? 0: CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000642 }
643
644 /* Draw windows */
645 if(windows != NULL) {
646 /* Find the last window.*/
647 for(w = windows; w->next != NULL; w = w->next);
648
649 /* Draw the windows from back to front. */
650 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000651 ctk_draw_clear_window(w, 0, clipy1, clipy2);
oliverschmidtadf27db2005-03-15 15:51:17 +0000652 ctk_draw_window(w, 0, clipy1, clipy2, 1);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000653 }
oliverschmidte99386b2004-12-27 22:03:04 +0000654
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000655 /* Draw focused window */
oliverschmidte99386b2004-12-27 22:03:04 +0000656 focus = mode == CTK_MODE_WINDOWMOVE?
657 CTK_FOCUS_WIDGET|CTK_FOCUS_WINDOW:
658 CTK_FOCUS_WINDOW;
659 ctk_draw_clear_window(windows, focus, clipy1, clipy2);
oliverschmidtadf27db2005-03-15 15:51:17 +0000660 ctk_draw_window(windows, focus, clipy1, clipy2, 1);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000661 }
662
663 /* Draw dialog (if any) */
664 if(dialog != NULL) {
665 ctk_draw_dialog(dialog);
666 }
667
668#if CTK_CONF_MENUS
669 ctk_draw_menus(&menus);
670#endif /* CTK_CONF_MENUS */
671}
672/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000673/**
674 * Redraw the entire desktop.
675 *
676 * \param d The desktop to be redrawn.
677 *
678 * \note Currently the parameter d is not used, but must be set to
679 * NULL.
adamdunkelse937ded2003-10-01 07:53:57 +0000680 *
adamdunkels35298692003-08-31 22:16:49 +0000681 */
682/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000683void
adamdunkels965e2922003-06-30 20:44:57 +0000684ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000685{
adamdunkels3b548c82004-07-04 11:41:39 +0000686 if(EK_CURRENT() == &p) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000687 if(mode == CTK_MODE_NORMAL ||
688 mode == CTK_MODE_WINDOWMOVE) {
689 do_redraw_all(1, height);
690 }
691 } else {
692 redraw |= REDRAW_ALL;
693 }
694}
695/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000696/**
697 * Redraw a window.
698 *
699 * This function redraws the window, but only if it is the foremost
700 * one on the desktop.
701 *
702 * \param w The window to be redrawn.
703 */
704/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000705void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000706ctk_window_redraw(struct ctk_window *w)
707{
708 /* Only redraw the window if it is a dialog or if it is the foremost
709 window. */
710 if(mode != CTK_MODE_NORMAL) {
711 return;
712 }
713
714 if(w == dialog) {
715 ctk_draw_dialog(w);
716 } else if(dialog == NULL &&
717#if CTK_CONF_MENUS
718 menus.open == NULL &&
719#endif /* CTK_CONF_MENUS */
720 windows == w) {
721 ctk_draw_window(w, CTK_FOCUS_WINDOW,
oliverschmidtadf27db2005-03-15 15:51:17 +0000722 0, height, 0);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000723 }
724}
725/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000726/**
727 * \internal Creates a new window.
728 *
729 * \param window The window to be created.
730 * \param w The width of the window.
731 * \param h The height of the window.
732 * \param title The title of the window.
733 */
734/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000735static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000736window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000737 unsigned char w, unsigned char h,
738 char *title)
739{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000740
741 if(w >= width - 2) {
742 window->x = 0;
743 } else {
744 window->x = (width - w - 2) / 2;
745 }
oliverschmidt432bc5a2004-12-22 22:52:53 +0000746 if(h >= height - 2 - ctk_draw_windowtitle_height) {
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000747 window->y = 0;
748 } else {
oliverschmidt432bc5a2004-12-22 22:52:53 +0000749 window->y = (height - h - 2 - ctk_draw_windowtitle_height) / 2;
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000750 }
751
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000752 window->w = w;
753 window->h = h;
754 window->title = title;
755 if(title != NULL) {
756 window->titlelen = strlen(title);
757 } else {
758 window->titlelen = 0;
759 }
760 window->next = window->prev = NULL;
adamdunkels3b548c82004-07-04 11:41:39 +0000761 /* window->owner = DISPATCHER_CURRENT();*/
762 window->owner = EK_PROC_ID(EK_CURRENT());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000763 window->active = window->inactive = window->focused = NULL;
764}
765/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000766/**
767 * Create a new window.
768 *
769 * Creates a new window. The memory for the window structure must
770 * already be allocated by the caller, and is usually done with a
771 * static declaration.
772 *
773 * This function sets up the internal structure of the ctk_window
774 * struct and creates the move and close buttons, but it does not open
775 * the window. The window must be explicitly opened by calling the
776 * ctk_window_open() function.
777 *
778 * \param window The window to be created.
779 * \param w The width of the new window.
780 * \param h The height of the new window.
781 * \param title The title of the new window.
782 */
783/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000784void
785ctk_window_new(struct ctk_window *window,
786 unsigned char w, unsigned char h,
787 char *title)
788{
789 window_new(window, w, h, title);
790
791 make_windowbuttons(window);
792}
793/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000794/**
795 * Creates a new dialog.
796 *
797 * This function only sets up the internal structure of the ctk_window
798 * struct but does not open the dialog. The dialog must be explicitly
799 * opened by calling the ctk_dialog_open() function.
800 *
801 * \param dialog The dialog to be created.
802 * \param w The width of the dialog.
803 * \param h The height of the dialog.
804 */
805/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000806void
adamdunkels35298692003-08-31 22:16:49 +0000807ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808 unsigned char w, unsigned char h)
809{
adamdunkels35298692003-08-31 22:16:49 +0000810 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000811}
adamdunkels3af580f2003-08-11 22:27:13 +0000812/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000813/**
814 * Creates a new menu.
815 *
816 * This function sets up the internal structure of the menu, but does
817 * not add it to the menubar. Use the function ctk_menu_add() for that
818 * purpose.
819 *
820 * \param menu The menu to be created.
821 * \param title The title of the menu.
822 */
823/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000824void
adamdunkelsd07a5422003-04-05 12:22:35 +0000825ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826 char *title)
827{
828#if CTK_CONF_MENUS
829 menu->next = NULL;
830 menu->title = title;
831 menu->titlelen = strlen(title);
832 menu->active = 0;
833 menu->nitems = 0;
834#endif /* CTK_CONF_MENUS */
835}
836/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000837/**
838 * Adds a menu item to a menu.
839 *
840 * In CTK, each menu item is identified by a number which is unique
841 * within each menu. When a menu item is selected, a
842 * ctk_menuitem_activated signal is emitted and the menu item number
843 * is passed as signal data with the signal.
844 *
845 * \param menu The menu to which the menu item should be added.
846 * \param name The name of the menu item.
847 * \return The number of the menu item.
848 */
849/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000850unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000851ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000852 char *name)
853{
854#if CTK_CONF_MENUS
855 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
856 return 0;
857 }
858 menu->items[menu->nitems].title = name;
859 menu->items[menu->nitems].titlelen = strlen(name);
860 return menu->nitems++;
861#else
862 return 0;
863#endif /* CTK_CONF_MENUS */
864}
865/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000866/**
867 * \internal Adds a widget to the list of widgets that should be
868 * redrawn.
869 *
870 * \param w The widget that should be redrawn.
871 */
872/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000873static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000874add_redrawwidget(struct ctk_widget *w)
875{
876 static unsigned char i;
877
878 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
879 redraw |= REDRAW_FOCUS;
880 } else {
881 redraw |= REDRAW_WIDGETS;
882 /* Check if it is in the queue already. If so, we don't add it
883 again. */
884 for(i = 0; i < redraw_widgetptr; ++i) {
885 if(redraw_widgets[i] == w) {
886 return;
887 }
888 }
889 redraw_widgets[redraw_widgetptr++] = w;
890 }
891}
892/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000893/**
894 * \internal Checks if a widget redrawn and adds it to the list of
895 * widgets to be redrawn.
896 *
897 * A widget can be redrawn only if the current CTK mode is
898 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
899 * foremost window.
900 *
901 * \param widget The widget that should be redrawn.
902 */
903/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000904static void
905widget_redraw(struct ctk_widget *widget)
906{
907 struct ctk_window *window;
908
909 if(mode != CTK_MODE_NORMAL || widget == NULL) {
910 return;
911 }
912
913 /* Only redraw widgets that are in the foremost window. If we would
914 allow redrawing widgets in non-focused windows, we would have to
915 redraw all the windows that cover the non-focused window as well,
916 which would lead to flickering.
917
918 Also, we avoid drawing any widgets when the menus are active.
919 */
920
921#if CTK_CONF_MENUS
922 if(menus.open == NULL)
923#endif /* CTK_CONF_MENUS */
924 {
925 window = widget->window;
926 if(window == dialog) {
927 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
928 } else if(dialog == NULL &&
929 (window == windows ||
930 window == &desktop_window)) {
931 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
932 }
933 }
934}
935/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000936/**
937 * Redraws a widget.
938 *
939 * This function will set a flag which causes the widget to be redrawn
940 * next time the CTK process is scheduled.
941 *
942 * \param widget The widget that is to be redrawn.
943 *
944 * \note This function should usually not be called directly since it
945 * requires typecasting of the widget parameter. The wrapper macro
946 * CTK_WIDGET_REDRAW() does the required typecast and should be used
947 * instead.
948 */
949/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000950void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000951ctk_widget_redraw(struct ctk_widget *widget)
952{
adamdunkels9f667f22003-04-16 18:29:19 +0000953 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000954 return;
955 }
956
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000957 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000959 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000960}
961/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000962/**
963 * Adds a widget to a window.
964 *
965 * This function adds a widget to a window. The order of which the
966 * widgets are added is important, as it sets the order to which
967 * widgets are cycled with the widget selection keys.
968 *
969 * \param window The window to which the widhet should be added.
970 * \param widget The widget to be added.
971 */
972/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000973void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000974ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
975 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000976{
977 if(widget->type == CTK_WIDGET_LABEL ||
978 widget->type == CTK_WIDGET_SEPARATOR) {
979 widget->next = window->inactive;
980 window->inactive = widget;
981 widget->window = window;
982 } else {
983 widget->next = window->active;
984 window->active = widget;
985 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000986 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000987 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000988 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000989 }
990}
991/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000992/**
993 * Gets the width of the desktop.
994 *
995 * \param d The desktop.
996 * \return The width of the desktop, in characters.
997 *
998 * \note The d parameter is currently unused and must be set to NULL.
999 */
1000/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001001unsigned char
adamdunkels35298692003-08-31 22:16:49 +00001002ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001003{
1004 return ctk_draw_width();
1005}
1006/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +00001007/**
1008 * Gets the height of the desktop.
1009 *
1010 * \param d The desktop.
1011 * \return The height of the desktop, in characters.
1012 *
1013 * \note The d parameter is currently unused and must be set to NULL.
1014 */
1015/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001016unsigned char
adamdunkels35298692003-08-31 22:16:49 +00001017ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001018{
1019 return ctk_draw_height();
1020}
1021/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +00001022/**
1023 * \internal Selects a widget in the window of the widget.
1024 *
1025 * \param focus The widget to be focused.
1026 */
1027/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001028static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +00001029select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +00001030{
1031 struct ctk_window *window;
1032
1033 window = focus->window;
1034
1035 if(focus != window->focused) {
1036 window->focused = focus;
1037 /* The operation changed the focus, so we emit a "hover" signal
1038 for those widgets that support it. */
1039
1040 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001041 ek_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001042 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001043 ek_post(window->owner, ctk_signal_button_hover, window->focused);
adamdunkelse0683312003-04-09 09:02:52 +00001044 }
1045
1046 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +00001047
adamdunkels3b548c82004-07-04 11:41:39 +00001048 ek_post(focus->window->owner, ctk_signal_widget_select, focus);
adamdunkels58917a82003-04-18 00:18:38 +00001049
adamdunkelse0683312003-04-09 09:02:52 +00001050 }
1051
1052}
1053/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001054#define UP 0
1055#define DOWN 1
1056#define LEFT 2
1057#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +00001058static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001059switch_focus_widget(unsigned char direction)
1060{
1061 register struct ctk_window *window;
1062 register struct ctk_widget *focus;
1063 struct ctk_widget *widget;
1064
1065
1066 if(dialog != NULL) {
1067 window = dialog;
1068 } else {
1069 window = windows;
1070 }
1071
1072 /* If there are no windows open, we move focus around between the
1073 icons on the root window instead. */
1074 if(window == NULL) {
1075 window = &desktop_window;
1076 }
1077
1078 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +00001079 if(focus == NULL) {
1080 focus = window->active;
adamdunkels6b9d5e82004-09-19 15:24:19 +00001081 if(focus == NULL) {
1082 return;
1083 }
adamdunkelse8bdfe12003-04-25 08:49:17 +00001084 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001085 add_redrawwidget(focus);
1086
1087 if((direction & 1) == 0) {
1088 /* Move focus "up" */
1089 focus = focus->next;
1090 } else {
1091 /* Move focus "down" */
1092 for(widget = window->active;
1093 widget != NULL; widget = widget->next) {
1094 if(widget->next == focus) {
1095 break;
1096 }
1097 }
1098 focus = widget;
1099 if(focus == NULL) {
1100 if(window->active != NULL) {
1101 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001102 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001103 }
1104 }
1105 }
1106 if(focus == NULL) {
1107 focus = window->active;
1108 }
adamdunkelse0683312003-04-09 09:02:52 +00001109
adamdunkelsb2486562003-04-11 20:22:03 +00001110 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001111}
1112/*-----------------------------------------------------------------------------------*/
1113#if CTK_CONF_MENUS
1114static void
1115switch_open_menu(unsigned char rightleft)
1116{
1117 struct ctk_menu *menu;
1118
1119 if(rightleft == 0) {
1120 /* Move right */
1121 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1122 if(menu->next == menus.open) {
1123 break;
1124 }
1125 }
1126 lastmenu = menus.open;
1127 menus.open = menu;
1128 if(menus.open == NULL) {
1129 for(menu = menus.menus;
1130 menu->next != NULL; menu = menu->next);
1131 menus.open = menu;
1132 }
1133 } else {
1134 /* Move to left */
1135 lastmenu = menus.open;
1136 menus.open = menus.open->next;
1137 if(menus.open == NULL) {
1138 menus.open = menus.menus;
1139 }
1140 }
1141
adamdunkels66109622003-04-24 17:17:10 +00001142 menus.open->active = 0;
1143
1144 /* if(menus.open->nitems > maxnitems) {
1145 maxnitems = menus.open->nitems;
1146 }*/
1147
adamdunkels965e2922003-06-30 20:44:57 +00001148 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001149}
1150/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001151static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001152switch_menu_item(unsigned char updown)
1153{
1154 register struct ctk_menu *m;
1155
1156 m = menus.open;
1157
1158 if(updown == 0) {
1159 /* Move up */
1160 if(m->active == 0) {
1161 m->active = m->nitems - 1;
1162 } else {
1163 --m->active;
1164 if(m->items[m->active].title[0] == '-') {
1165 --m->active;
1166 }
1167 }
1168 } else {
1169 /* Move down */
1170 if(m->active >= m->nitems - 1) {
1171 m->active = 0;
1172 } else {
1173 ++m->active;
1174 if(m->items[m->active].title[0] == '-') {
1175 ++m->active;
1176 }
1177 }
1178 }
1179
1180}
1181#endif /* CTK_CONF_MENUS */
1182/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001183static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001184activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001185{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001186 if(w->type == CTK_WIDGET_BUTTON) {
1187 if(w == (struct ctk_widget *)&windows->closebutton) {
1188#if CTK_CONF_WINDOWCLOSE
adamdunkels3b548c82004-07-04 11:41:39 +00001189 ek_post(w->window->owner, ctk_signal_window_close, windows);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001190 ctk_window_close(windows);
1191 return REDRAW_ALL;
1192#endif /* CTK_CONF_WINDOWCLOSE */
1193 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
oliverschmidte99386b2004-12-27 22:03:04 +00001194#if CTK_CONF_WINDOWMOVE
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001195 mode = CTK_MODE_WINDOWMOVE;
oliverschmidte99386b2004-12-27 22:03:04 +00001196 return REDRAW_ALL;
1197#endif /* CTK_CONF_WINDOWMOVE */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001198 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001199 ek_post(w->window->owner, ctk_signal_widget_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001200 }
1201#if CTK_CONF_ICONS
1202 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels3b548c82004-07-04 11:41:39 +00001203 if(w->widget.icon.owner != EK_ID_NONE) {
1204 ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
1205 } else {
1206 ek_post(w->window->owner, ctk_signal_widget_activate, w);
1207 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001208#endif /* CTK_CONF_ICONS */
1209 } else if(w->type == CTK_WIDGET_HYPERLINK) {
adamdunkels3b548c82004-07-04 11:41:39 +00001210 ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001211 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1212 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
oliverschmidt11511242005-05-04 23:05:37 +00001213 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1214 textentry_input(0, (struct ctk_textentry *)w);
oliverschmidtf28743b2005-05-04 22:33:45 +00001215 } else {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001216 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
PulkoMandy3e213902014-06-26 11:08:29 +02001234 if(t->input != NULL && t->input(c, (void*)t)) {
1235 return;
oliverschmidt0096f6a2005-05-04 21:50:17 +00001236 }
1237
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001238 txpos = t->xpos;
1239 typos = t->ypos;
1240 tlen = t->len;
1241
oliverschmidtcd6c30b2005-05-05 20:54:16 +00001242 cptr = &t->text[txpos + typos * (tlen + 1)];
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001243
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
oliverschmidt11511242005-05-04 23:05:37 +00001261 case 0:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001262 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001263 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001264 if(txpos == tlen) {
1265 --txpos;
1266 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001267 break;
1268
1269 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001270 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1271 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001272 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001273 break;
1274
adamdunkels9795b2e2003-08-09 23:32:37 +00001275 case CTK_CONF_WIDGETDOWN_KEY:
1276 t->state = CTK_TEXTENTRY_NORMAL;
1277 switch_focus_widget(DOWN);
1278 break;
1279 case CTK_CONF_WIDGETUP_KEY:
1280 t->state = CTK_TEXTENTRY_NORMAL;
1281 switch_focus_widget(UP);
1282 break;
1283
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001284 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001285 len = tlen - txpos;
1286 if(c == CH_DEL) {
1287 if(len == 1 && *cptr != 0) {
1288 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001289 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001290 if(txpos > 0) {
1291 --txpos;
1292 strcpy(cptr - 1, cptr);
1293 }
1294 }
1295 } else {
1296 if(ctk_arch_isprint(c)) {
1297 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001298 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001299 while(cptr2 > cptr) {
1300 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001301 --cptr2;
1302 }
adamdunkelsc9619082004-06-06 06:19:25 +00001303 ++txpos;
1304 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001305 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001306 }
1307 }
1308 break;
1309 }
1310
1311 t->xpos = txpos;
1312 t->ypos = typos;
1313}
1314/*-----------------------------------------------------------------------------------*/
1315#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001316static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001317activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001318{
1319 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001320
adamdunkelsb2486562003-04-11 20:22:03 +00001321 lastmenu = menus.open;
1322 if(menus.open == &desktopmenu) {
1323 for(w = windows; w != NULL; w = w->next) {
1324 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1325 ctk_window_open(w);
1326 menus.open = NULL;
1327 return REDRAW_ALL;
1328 }
1329 }
1330 } else {
adamdunkels3b548c82004-07-04 11:41:39 +00001331 ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
adamdunkelsb2486562003-04-11 20:22:03 +00001332 }
1333 menus.open = NULL;
1334 return REDRAW_MENUPART;
1335}
1336/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001337static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001338menus_input(ctk_arch_key_t c)
1339{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001340
1341 if(menus.open->nitems > maxnitems) {
1342 maxnitems = menus.open->nitems;
1343 }
1344
1345
1346 switch(c) {
1347 case CH_CURS_RIGHT:
1348 switch_open_menu(1);
1349
1350 return REDRAW_MENUPART;
1351
1352 case CH_CURS_DOWN:
1353 switch_menu_item(1);
1354 return REDRAW_MENUS;
1355
1356 case CH_CURS_LEFT:
1357 switch_open_menu(0);
1358 return REDRAW_MENUPART;
1359
1360 case CH_CURS_UP:
1361 switch_menu_item(0);
1362 return REDRAW_MENUS;
1363
1364 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001365 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001366
adamdunkels88ed9c42003-03-28 12:10:09 +00001367 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001368 lastmenu = menus.open;
1369 menus.open = NULL;
1370 return REDRAW_MENUPART;
1371 }
adamdunkelsb2486562003-04-11 20:22:03 +00001372
1373 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001374}
1375#endif /* CTK_CONF_MENUS */
1376/*-----------------------------------------------------------------------------------*/
1377static void
adamdunkels3b548c82004-07-04 11:41:39 +00001378handle_timer(void)
adamdunkelscf90b0d2003-08-09 13:34:16 +00001379{
1380 if(mode == CTK_MODE_NORMAL) {
1381 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001382 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001383#if CTK_CONF_SCREENSAVER
adamdunkels3b548c82004-07-04 11:41:39 +00001384 ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001385#ifdef CTK_SCREENSAVER_INIT
1386 CTK_SCREENSAVER_INIT();
1387#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001388
adamdunkelscf90b0d2003-08-09 13:34:16 +00001389#endif /* CTK_CONF_SCREENSAVER */
1390 screensaver_timer = 0;
1391 }
1392 }
1393}
1394/*-----------------------------------------------------------------------------------*/
1395static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001396unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1397{
1398 if(w != NULL) {
1399 redraw |= REDRAW_WIDGETS;
1400 add_redrawwidget(w);
1401 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1402 ((struct ctk_textentry *)w)->state =
1403 CTK_TEXTENTRY_NORMAL;
1404 }
1405 w->window->focused = NULL;
1406 }
1407}
1408/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001409EK_POLLHANDLER(ctk_poll)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001410{
1411 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001412 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001413 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001414 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001415 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001416#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001417 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1418 mouse_clicked;
1419 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001420 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001421
adamdunkels19a787c2003-04-09 09:22:24 +00001422#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001423
1424
adamdunkels3b548c82004-07-04 11:41:39 +00001425 /* current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001426
adamdunkels9795b2e2003-08-09 23:32:37 +00001427 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001428 timer();
1429 start = current;
adamdunkels3b548c82004-07-04 11:41:39 +00001430 } */
1431 if(timer_expired(&timer)) {
1432 timer_reset(&timer);
1433 handle_timer();
1434 }
adamdunkelscf90b0d2003-08-09 13:34:16 +00001435
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001436#if CTK_CONF_MENUS
1437 if(menus.open != NULL) {
1438 maxnitems = menus.open->nitems;
1439 } else {
1440 maxnitems = 0;
1441 }
1442#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001443
1444#if CTK_CONF_MOUSE_SUPPORT
1445 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1446
1447 /* See if there is any change in the buttons. */
1448 if(ctk_mouse_button() != mouse_button) {
1449 mouse_button = ctk_mouse_button();
1450 mouse_button_changed = 1;
1451 if(mouse_button == 0) {
1452 mouse_clicked = 1;
1453 }
1454 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001455
adamdunkelsb2486562003-04-11 20:22:03 +00001456 /* Check if the mouse pointer has moved. */
1457 if(ctk_mouse_x() != mouse_x ||
1458 ctk_mouse_y() != mouse_y) {
1459 mouse_x = ctk_mouse_x();
1460 mouse_y = ctk_mouse_y();
1461 mouse_moved = 1;
1462 }
1463
1464 mxc = ctk_mouse_xtoc(mouse_x);
1465 myc = ctk_mouse_ytoc(mouse_y);
1466#endif /* CTK_CONF_MOUSE_SUPPORT */
1467
1468
adamdunkels66109622003-04-24 17:17:10 +00001469#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001470 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001471 if(ctk_arch_keyavail()
1472#if CTK_CONF_MOUSE_SUPPORT
1473 || mouse_moved || mouse_button_changed
1474#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001475 ) {
adamdunkels3b548c82004-07-04 11:41:39 +00001476 ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001477 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001478 }
adamdunkels66109622003-04-24 17:17:10 +00001479 } else
1480#endif /* CTK_CONF_SCREENSAVER */
1481 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001482#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001483 /* If there is any change in the mouse conditions, find out in
1484 which window the mouse pointer currently is in order to send
1485 the correct signals, or bring a window to focus. */
1486 if(mouse_moved || mouse_button_changed) {
1487 ctk_mouse_show();
1488 screensaver_timer = 0;
1489
1490 if(myc == 0) {
1491 /* Here we should do whatever needs to be done when the mouse
1492 moves around and clicks in the menubar. */
1493 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001494 static unsigned char titlelen;
1495
adamdunkelsb2486562003-04-11 20:22:03 +00001496 /* Find out which menu that the mouse pointer is in. Start
1497 with the ->next menu after the desktop menu. We assume
1498 that the menus start one character from the left screen
1499 side and that the desktop menu is farthest to the
1500 right. */
1501 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001502 for(menu = menus.menus->next;
1503 menu != NULL; menu = menu->next) {
1504 titlelen = menu->titlelen;
1505 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001506 break;
adamdunkelse0683312003-04-09 09:02:52 +00001507 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001508 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001509 }
adamdunkelsb2486562003-04-11 20:22:03 +00001510
1511 /* Also check desktop menu. */
1512 if(mxc >= width - 7 &&
1513 mxc <= width - 1) {
1514 menu = &desktopmenu;
1515 }
1516
1517 menus.open = menu;
1518 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001519 }
adamdunkelse0683312003-04-09 09:02:52 +00001520 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001521 --myc;
1522
1523 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001524 static unsigned char nitems;
1525
adamdunkelsb2486562003-04-11 20:22:03 +00001526 /* Do whatever needs to be done when a menu is open. */
1527
adamdunkelscf90b0d2003-08-09 13:34:16 +00001528 /* First check if the mouse pointer is in the currently open
1529 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001530 if(menus.open == &desktopmenu) {
1531 menux = width - CTK_CONF_MENUWIDTH;
1532 } else {
1533 menux = 1;
1534 for(menu = menus.menus->next; menu != menus.open;
1535 menu = menu->next) {
1536 menux += menu->titlelen;
1537 }
1538 }
1539
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001540 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001541 /* Find out which of the menu items the mouse is pointing
1542 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001543 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1544 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001545 menus.open->active = myc;
1546 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001547 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001548 }
adamdunkelsb2486562003-04-11 20:22:03 +00001549 }
1550
1551 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001552 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001553 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001554 redraw |= activate_menu();
1555 } else {
1556 lastmenu = menus.open;
1557 menus.open = NULL;
1558 redraw |= REDRAW_MENUPART;
1559 }
1560 } else {
1561 redraw |= REDRAW_MENUS;
1562 }
1563 } else {
1564
adamdunkels965e2922003-06-30 20:44:57 +00001565 /* Walk through the windows from top to bottom to see in
1566 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001567 if(dialog != NULL) {
1568 window = dialog;
1569 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001570 for(window = windows; window != NULL;
1571 window = window->next) {
1572
adamdunkelsb2486562003-04-11 20:22:03 +00001573 /* Check if the mouse is within the window. */
1574 if(mxc >= window->x &&
adamdunkels3b548c82004-07-04 11:41:39 +00001575 mxc <= window->x + window->w +
1576 2 * ctk_draw_windowborder_width &&
adamdunkelsb2486562003-04-11 20:22:03 +00001577 myc >= window->y &&
adamdunkels3b548c82004-07-04 11:41:39 +00001578 myc <= window->y + window->h +
1579 ctk_draw_windowtitle_height +
1580 ctk_draw_windowborder_height) {
adamdunkelsb2486562003-04-11 20:22:03 +00001581 break;
1582 }
1583 }
1584 }
1585
1586
1587 /* If we didn't find any window, and there are no windows
1588 open, the mouse pointer will definately be within the
1589 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001590 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001591 window = &desktop_window;
1592 }
1593
adamdunkels965e2922003-06-30 20:44:57 +00001594 /* If the mouse pointer moves around outside of the
1595 currently focused window (or dialog), we should not have
1596 any focused widgets in the focused window so we make sure
1597 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001598 if(windows != NULL &&
1599 window != windows &&
1600 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001601 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001602 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001603 redraw |= REDRAW_WIDGETS;*/
1604 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001605 }
1606
1607 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001608 /* If the mouse was clicked outside of the current window,
1609 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001610 if(dialog == NULL &&
1611 window != &desktop_window &&
1612 window != windows &&
1613 mouse_clicked) {
1614 /* Bring window to front. */
1615 ctk_window_open(window);
1616 redraw |= REDRAW_ALL;
1617 } else {
1618
adamdunkels965e2922003-06-30 20:44:57 +00001619 /* Find out which widget currently is under the mouse
1620 pointer and give it focus, unless it already has
1621 focus. */
adamdunkels3b548c82004-07-04 11:41:39 +00001622 mxc = mxc - window->x - ctk_draw_windowborder_width;
1623 myc = myc - window->y - ctk_draw_windowtitle_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001624
adamdunkels965e2922003-06-30 20:44:57 +00001625 /* See if the mouse pointer is on a widget. If so, it
1626 should be selected and, if the button is clicked,
1627 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001628 for(widget = window->active; widget != NULL;
1629 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001630
adamdunkelsb2486562003-04-11 20:22:03 +00001631 if(mxc >= widget->x &&
1632 mxc <= widget->x + widget->w &&
1633 (myc == widget->y ||
1634 ((widget->type == CTK_WIDGET_BITMAP ||
1635 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1636 widget->type == CTK_WIDGET_ICON) &&
1637 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001638 myc <= widget->y +
1639 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001640 break;
1641 }
1642 }
1643
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001644
1645 /* if the mouse is moved in the focused window, we emit
1646 a ctk_signal_pointer_move signal to the owner of the
1647 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001648 if(mouse_moved &&
1649 (window != &desktop_window ||
1650 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001651
adamdunkels3b548c82004-07-04 11:41:39 +00001652 ek_post(window->owner, ctk_signal_pointer_move, NULL);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001653
1654 /* If there was a focused widget that is not below the
1655 mouse pointer, we remove focus from the widget and
1656 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001657 if(window->focused != NULL &&
1658 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001659 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001660 if(CTK_WIDGET_TYPE(window->focused) ==
1661 CTK_WIDGET_TEXTENTRY) {
1662 ((struct ctk_textentry *)(window->focused))->state =
1663 CTK_TEXTENTRY_NORMAL;
1664 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001665 window->focused = NULL;*/
1666 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001667 }
1668 redraw |= REDRAW_WIDGETS;
1669 if(widget != NULL) {
1670 select_widget(widget);
1671 }
1672 }
1673
1674 if(mouse_button_changed) {
adamdunkels3b548c82004-07-04 11:41:39 +00001675 ek_post(window->owner, ctk_signal_pointer_button,
1676 (ek_data_t)mouse_button);
adamdunkelsb2486562003-04-11 20:22:03 +00001677 if(mouse_clicked && widget != NULL) {
1678 select_widget(widget);
1679 redraw |= activate(widget);
1680 }
1681 }
1682 }
1683 }
1684 }
adamdunkelsc4902862003-04-09 00:30:45 +00001685 }
1686 }
adamdunkels19a787c2003-04-09 09:22:24 +00001687#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001688
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001689 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001690
1691 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001692
1693 screensaver_timer = 0;
1694
adamdunkelsb2486562003-04-11 20:22:03 +00001695 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001696
1697 if(dialog != NULL) {
1698 window = dialog;
1699 } else if(windows != NULL) {
1700 window = windows;
1701 } else {
1702 window = &desktop_window;
adamdunkels54d32c72004-09-01 18:14:37 +00001703 }
1704
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001705 widget = window->focused;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001706
1707 if(widget != NULL &&
1708 widget->type == CTK_WIDGET_TEXTENTRY &&
1709 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1710 textentry_input(c, (struct ctk_textentry *)widget);
1711 add_redrawwidget(widget);
1712#if CTK_CONF_MENUS
1713 } else if(menus.open != NULL) {
1714 redraw |= menus_input(c);
1715#endif /* CTK_CONF_MENUS */
1716 } else {
1717 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001718 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001719 switch_focus_widget(DOWN);
1720 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001721 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001722 switch_focus_widget(UP);
1723 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001724#if CTK_CONF_MENUS
1725 case CTK_CONF_MENU_KEY:
1726 if(dialog == NULL) {
1727 if(lastmenu == NULL) {
1728 menus.open = menus.menus;
1729 } else {
1730 menus.open = lastmenu;
1731 }
1732 menus.open->active = 0;
1733 redraw |= REDRAW_MENUS;
1734 }
1735 break;
1736#endif /* CTK_CONF_MENUS */
1737 case CTK_CONF_WINDOWSWITCH_KEY:
1738 if(windows != NULL) {
1739 for(window = windows; window->next != NULL;
1740 window = window->next);
1741 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001742 }
1743 break;
1744 default:
adamdunkels54d32c72004-09-01 18:14:37 +00001745
adamdunkels3af580f2003-08-11 22:27:13 +00001746 if(c == CH_ENTER &&
1747 widget != NULL) {
1748 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001749 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001750 if(widget != NULL &&
1751 widget->type == CTK_WIDGET_TEXTENTRY) {
oliverschmidtf28743b2005-05-04 22:33:45 +00001752 if(widget->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
oliverschmidt11511242005-05-04 23:05:37 +00001753 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1754 textentry_input(0, (struct ctk_textentry *)widget);
oliverschmidtf28743b2005-05-04 22:33:45 +00001755 }
adamdunkels3af580f2003-08-11 22:27:13 +00001756 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001757 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001758 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001759 /* window->focused = NULL;*/
1760 unfocus_widget(window->focused);
adamdunkels54d32c72004-09-01 18:14:37 +00001761 ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
adamdunkels3af580f2003-08-11 22:27:13 +00001762 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001763 }
1764 break;
1765 }
1766 }
1767
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001768#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001769 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001770 widgetptr = redraw_widgets;
1771 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001772 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001773 *widgetptr = NULL;
1774 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001775 }
1776 redraw &= ~REDRAW_WIDGETS;
1777 redraw_widgetptr = 0;
1778 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001779#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001780 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001781#if CTK_CONF_WINDOWMOVE
1782 } else if(mode == CTK_MODE_WINDOWMOVE) {
1783
1784 redraw = 0;
1785
1786 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001787
1788#if CTK_CONF_MOUSE_SUPPORT
1789
1790 /* If the mouse has moved, we move the window as well. */
1791 if(mouse_moved) {
1792
1793 if(window->w + mxc + 2 >= width) {
1794 window->x = width - 2 - window->w;
1795 } else {
1796 window->x = mxc;
1797 }
1798
adamdunkels3b548c82004-07-04 11:41:39 +00001799 if(window->h + myc + ctk_draw_windowtitle_height +
1800 ctk_draw_windowborder_height >= height) {
1801 window->y = height - window->h -
1802 ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
adamdunkelsb2486562003-04-11 20:22:03 +00001803 } else {
1804 window->y = myc;
1805 }
1806 if(window->y > 0) {
1807 --window->y;
1808 }
1809
1810 redraw = REDRAW_ALL;
1811 }
1812
1813 /* Check if the mouse has been clicked, and stop moving the window
1814 if so. */
1815 if(mouse_button_changed &&
1816 mouse_button == 0) {
1817 mode = CTK_MODE_NORMAL;
1818 redraw = REDRAW_ALL;
1819 }
1820#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001821
1822 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1823
1824 screensaver_timer = 0;
1825
1826 c = ctk_arch_getkey();
1827
1828 switch(c) {
1829 case CH_CURS_RIGHT:
1830 ++window->x;
1831 if(window->x + window->w + 1 >= width) {
1832 --window->x;
1833 }
1834 redraw = REDRAW_ALL;
1835 break;
1836 case CH_CURS_LEFT:
1837 if(window->x > 0) {
1838 --window->x;
1839 }
1840 redraw = REDRAW_ALL;
1841 break;
1842 case CH_CURS_DOWN:
1843 ++window->y;
1844 if(window->y + window->h + 2 >= height) {
1845 --window->y;
1846 }
1847 redraw = REDRAW_ALL;
1848 break;
1849 case CH_CURS_UP:
1850 if(window->y > 0) {
1851 --window->y;
1852 }
1853 redraw = REDRAW_ALL;
1854 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001855 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001856 mode = CTK_MODE_NORMAL;
1857 redraw = REDRAW_ALL;
1858 break;
1859 }
1860 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001861#endif /* CTK_CONF_WINDOWMOVE */
1862 }
adamdunkelsb2486562003-04-11 20:22:03 +00001863
1864 if(redraw & REDRAW_ALL) {
1865 do_redraw_all(1, height);
1866#if CTK_CONF_MENUS
1867 } else if(redraw & REDRAW_MENUPART) {
1868 do_redraw_all(1, maxnitems + 1);
1869 } else if(redraw & REDRAW_MENUS) {
1870 ctk_draw_menus(&menus);
1871#endif /* CTK_CONF_MENUS */
1872 } else if(redraw & REDRAW_FOCUS) {
1873 if(dialog != NULL) {
1874 ctk_window_redraw(dialog);
1875 } else if(windows != NULL) {
1876 ctk_window_redraw(windows);
1877 } else {
1878 ctk_window_redraw(&desktop_window);
1879 }
1880 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001881 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001882 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001883 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001884 *widgetptr = NULL;
1885 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001886 }
1887 }
1888 redraw = 0;
1889 redraw_widgetptr = 0;
1890
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001891}
1892/*-----------------------------------------------------------------------------------*/
adamdunkels3b548c82004-07-04 11:41:39 +00001893EK_EVENTHANDLER(ctk_eventhandler, ev, data)
1894{
1895
1896}
1897/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001898/** @} */
1899/** @} */
1900