blob: c8e2e6b4d1d697c8fb9868bb12057ba1fd14dfe8 [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 *
44 * This file is part of the "ctk" console GUI toolkit for cc65
45 *
adamdunkelse937ded2003-10-01 07:53:57 +000046 * $Id: ctk.c,v 1.34 2003/10/01 07:53:57 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000047 *
48 */
49
adamdunkelsd07a5422003-04-05 12:22:35 +000050#include "cc.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000051#include "ek.h"
52#include "dispatcher.h"
53#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
adamdunkels591724c2003-08-01 00:07:19 +000058#include <string.h>
59
adamdunkelsca9ddcb2003-03-19 14:13:31 +000060static unsigned char height, width;
61
62static unsigned char mode;
63
64static struct ctk_window desktop_window;
65static struct ctk_window *windows;
66static struct ctk_window *dialog;
67
68#if CTK_CONF_MENUS
69static struct ctk_menus menus;
70static struct ctk_menu *lastmenu;
71static struct ctk_menu desktopmenu;
72#endif /* CTK_CONF_MENUS */
73
74#ifndef NULL
75#define NULL (void *)0
76#endif /* NULL */
77
adamdunkelsca9ddcb2003-03-19 14:13:31 +000078#define REDRAW_NONE 0
79#define REDRAW_ALL 1
80#define REDRAW_FOCUS 2
81#define REDRAW_WIDGETS 4
82#define REDRAW_MENUS 8
83#define REDRAW_MENUPART 16
84
85#define MAX_REDRAWWIDGETS 4
86static unsigned char redraw;
87static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
88static unsigned char redraw_widgetptr;
89static unsigned char maxnitems;
90
91static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000092#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000094#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000095#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000096#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000097
adamdunkelsc4902862003-04-09 00:30:45 +000098static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000099static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +0000100 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000101static ek_id_t ctkid;
102
adamdunkelse937ded2003-10-01 07:53:57 +0000103/** @} */
104
105/**
106 * \addtogroup signals System signals
107 * @{
108 */
adamdunkels35298692003-08-31 22:16:49 +0000109ek_signal_t
110
adamdunkelse937ded2003-10-01 07:53:57 +0000111 /**
112 * Emitted for every key being pressed.
113 *
114 * The key is passed as signal data.*/
adamdunkels35298692003-08-31 22:16:49 +0000115 ctk_signal_keypress,
116
117 /** Emitted when a widget is activated (pressed). A pointer to the
118 widget is passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000119 ctk_signal_widget_activate,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000120
adamdunkelse937ded2003-10-01 07:53:57 +0000121 /** Same as ctk_signal_widget_activate. */
adamdunkels35298692003-08-31 22:16:49 +0000122 ctk_signal_button_activate,
123
124 /** Emitted when a widget is selected. A pointer to the widget is
125 passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000126 ctk_signal_widget_select,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000127
adamdunkelse937ded2003-10-01 07:53:57 +0000128 /** Same as ctk_signal_widget_select. */
adamdunkels35298692003-08-31 22:16:49 +0000129 ctk_signal_button_hover,
130
131 /** Emitted when a hyperlink is activated. The signal is broadcast
132 to all listeners. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000133 ctk_signal_hyperlink_activate,
adamdunkels35298692003-08-31 22:16:49 +0000134
adamdunkelse937ded2003-10-01 07:53:57 +0000135 /** Same as ctk_signal_widget_select. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000136 ctk_signal_hyperlink_hover,
adamdunkels35298692003-08-31 22:16:49 +0000137
138 /** Emitted when a menu item is activated. The number of the menu
139 item is passed as signal data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000140 ctk_signal_menu_activate,
adamdunkels35298692003-08-31 22:16:49 +0000141
142 /** Emitted when a window is closed. A pointer to the window is
143 passed as signal data. */
adamdunkelsc4902862003-04-09 00:30:45 +0000144 ctk_signal_window_close,
adamdunkels35298692003-08-31 22:16:49 +0000145
146 /** Emitted when the mouse pointer is moved. A NULL pointer is
147 passed as signal data and it is up to the listening process to
148 check the position of the mouse using the CTK mouse API.*/
adamdunkelsc4902862003-04-09 00:30:45 +0000149 ctk_signal_pointer_move,
adamdunkels35298692003-08-31 22:16:49 +0000150
151 /** Emitted when a mouse button is pressed. The button is passed as
152 signal data to the listening process. */
adamdunkelsb2486562003-04-11 20:22:03 +0000153 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000154
adamdunkels66109622003-04-24 17:17:10 +0000155#if CTK_CONF_SCREENSAVER
adamdunkelse937ded2003-10-01 07:53:57 +0000156/** Emitted when the user has been idle long enough for the
157 screensaver to start. */
adamdunkels9795b2e2003-08-09 23:32:37 +0000158ek_signal_t ctk_signal_screensaver_stop,
adamdunkelse937ded2003-10-01 07:53:57 +0000159 /** Emitted when the user presses a key or moves the mouse when the
160 screensaver is active. */
adamdunkels9795b2e2003-08-09 23:32:37 +0000161 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000162#endif /* CTK_CONF_SCREENSAVER */
163
adamdunkelse937ded2003-10-01 07:53:57 +0000164/** @} */
165
166/**
167 * \addtogroup ctk
168 * @{
169 */
adamdunkels66109622003-04-24 17:17:10 +0000170
adamdunkels19a787c2003-04-09 09:22:24 +0000171#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000172unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000173#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000174
adamdunkels9795b2e2003-08-09 23:32:37 +0000175static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000176unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels9795b2e2003-08-09 23:32:37 +0000177static ek_clock_t start, current;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000178
179#if CTK_CONF_MENUS
180/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000181/**
182 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000183 *
184 * Creates the leftmost menu, "Desktop". Since the desktop menu
185 * contains the list of all open windows, this function will be called
186 * whenever a window is opened or closed.
187 */
adamdunkels35298692003-08-31 22:16:49 +0000188/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000189static void
190make_desktopmenu(void)
191{
192 struct ctk_window *w;
193
194 desktopmenu.nitems = 0;
195
196 if(windows == NULL) {
197 ctk_menuitem_add(&desktopmenu, "(No windows)");
198 } else {
199 for(w = windows; w != NULL; w = w->next) {
200 ctk_menuitem_add(&desktopmenu, w->title);
201 }
202 }
203}
204#endif /* CTK_CONF_MENUS */
205/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000206/**
207 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000208 *
adamdunkels35298692003-08-31 22:16:49 +0000209 * This function must be called before any other CTK function, but
210 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000211 */
adamdunkels35298692003-08-31 22:16:49 +0000212/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000213void
214ctk_init(void)
215{
216 ctkid = dispatcher_start(&p);
217
218 windows = NULL;
219 dialog = NULL;
220
221#if CTK_CONF_MENUS
222 ctk_menu_new(&desktopmenu, "Desktop");
223 make_desktopmenu();
224 menus.menus = menus.desktopmenu = &desktopmenu;
225#endif /* CTK_CONF_MENUS */
226
adamdunkelsb2486562003-04-11 20:22:03 +0000227#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000228 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000229 ctk_mouse_show();
230#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000231
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000232 ctk_draw_init();
233
234 height = ctk_draw_height();
235 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000236
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000237 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000238
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000239 ctk_signal_keypress = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000240
241 ctk_signal_button_activate =
242 ctk_signal_widget_activate = dispatcher_sigalloc();
243
244 ctk_signal_button_hover =
245 ctk_signal_hyperlink_hover =
246 ctk_signal_widget_select = dispatcher_sigalloc();
247
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000248 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000249
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000250 ctk_signal_menu_activate = dispatcher_sigalloc();
251 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000252
253 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000254 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000255
256
257#if CTK_CONF_SCREENSAVER
258 ctk_signal_screensaver_start = dispatcher_sigalloc();
259 ctk_signal_screensaver_stop = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000260#endif /* CTK_CONF_SCREENSAVER */
261
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000262
263 mode = CTK_MODE_NORMAL;
264
265 iconx = ICONX_START;
266 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000267
268 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000269
270 start = ek_clock();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000271}
adamdunkelse937ded2003-10-01 07:53:57 +0000272
273/**
274 * \addtogroup ctkappfunc
275 * @{
276 */
277
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000278/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000279/**
280 * Sets the current CTK mode.
281 *
282 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
283 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
284 * keypresses and mouse pointer movements are processed and the screen
285 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
286 * performed and the first key press or pointer movement will cause
287 * the ctk_signal_screensaver_stop to be emitted. In the
288 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
289 * ignored and no screen redraws are made.
290 *
291 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000292 */
adamdunkels35298692003-08-31 22:16:49 +0000293/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000294void
295ctk_mode_set(unsigned char m) {
296 mode = m;
297}
298/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000299/**
300 * Retrieves the current CTK mode.
301 *
302 * \return The current CTK mode.
303 */
304/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000305unsigned char
306ctk_mode_get(void) {
307 return mode;
308}
309/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000310/**
311 * Add an icon to the desktop.
312 *
313 * \param icon The icon to be added.
adamdunkels0404ef12003-09-04 19:36:04 +0000314 *
315 * \param id The process ID of the process that owns the icon.
adamdunkels35298692003-08-31 22:16:49 +0000316 */
317/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000318void
adamdunkels0404ef12003-09-04 19:36:04 +0000319ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, ek_id_t id)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000320{
adamdunkels0404ef12003-09-04 19:36:04 +0000321#if CTK_CONF_ICONS
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322 icon->x = iconx;
323 icon->y = icony;
adamdunkels0404ef12003-09-04 19:36:04 +0000324 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000325
326 icony += ICONY_DELTA;
327 if(icony >= ICONY_MAX) {
328 icony = ICONY_START;
329 iconx += ICONX_DELTA;
330 }
331
332 ctk_widget_add(&desktop_window, icon);
333#endif /* CTK_CONF_ICONS */
334}
335/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000336/**
337 * Open a dialog box.
338 *
339 * \param d The dialog to be opened.
340 */
341/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000342void
343ctk_dialog_open(struct ctk_window *d)
344{
345 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000346 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000347}
348/*-----------------------------------------------------------------------------------*/
349/**
350 * Close the dialog box, if one is open.
351 *
352 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000353/*-----------------------------------------------------------------------------------*/
354void
355ctk_dialog_close(void)
356{
357 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000358 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000359}
360/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000361/**
362 * Open a window, or bring window to front if already open.
363 *
364 * \param w The window to be opened.
365 */
366/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000367void
adamdunkelsd07a5422003-04-05 12:22:35 +0000368ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000369{
370 struct ctk_window *w2;
371
372 /* Check if already open. */
373 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
374 if(w2 == NULL) {
375 /* Not open, so we add it at the head of the list of open
376 windows. */
377 w->next = windows;
378 if(windows != NULL) {
379 windows->prev = w;
380 }
381 windows = w;
382 w->prev = NULL;
383 } else {
384 /* Window already open, so we move it to the front of the windows
385 list. */
386 if(w != windows) {
387 if(w->next != NULL) {
388 w->next->prev = w->prev;
389 }
390 if(w->prev != NULL) {
391 w->prev->next = w->next;
392 }
393 w->next = windows;
394 windows->prev = w;
395 windows = w;
396 w->prev = NULL;
397 }
398 }
399
400#if CTK_CONF_MENUS
401 /* Recreate the Desktop menu's window entries.*/
402 make_desktopmenu();
403#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000404
405 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000406}
407/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000408/**
409 * Close a window if it is open.
410 *
411 * If the window is not open, this function does nothing.
412 *
413 * \param w The window to be closed.
414 */
415/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000416void
417ctk_window_close(struct ctk_window *w)
418{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000419 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000420
421 if(w == NULL) {
422 return;
423 }
424
425 /* Check if the window to be closed is the first window on the
426 list. */
427 if(w == windows) {
428 windows = w->next;
429 if(windows != NULL) {
430 windows->prev = NULL;
431 }
432 w->next = w->prev = NULL;
433 } else {
434 /* Otherwise we step through the list until we find the window
435 before the one to be closed. We then redirect its ->next
436 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000437 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
438
439 if(w2 == NULL) {
440 /* The window wasn't open, so there is nothing more for us to
441 do. */
442 return;
443 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000444
445 if(w->next != NULL) {
446 w->next->prev = w->prev;
447 }
448 w2->next = w->next;
449
450 w->next = w->prev = NULL;
451 }
452
453#if CTK_CONF_MENUS
454 /* Recreate the Desktop menu's window entries.*/
455 make_desktopmenu();
456#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000457 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458}
459/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000460/**
461 * \internal Create the move and close buttons on the window titlebar.
462 */
463/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000464static void
465make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000466{
467#if CTK_CONF_WINDOWMOVE
468 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
469#else
470 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
471#endif /* CTK_CONF_WINDOWMOVE */
472 CTK_WIDGET_ADD(window, &window->titlebutton);
473
474
475#if CTK_CONF_WINDOWCLOSE
476 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
477#else
478 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
479#endif /* CTK_CONF_WINDOWCLOSE */
480 CTK_WIDGET_ADD(window, &window->closebutton);
481}
482/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000483/**
484 * Remove all widgets from a window.
485 *
486 * \param w The window to be cleared.
487 */
488/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000489void
adamdunkels35298692003-08-31 22:16:49 +0000490ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000491{
adamdunkels35298692003-08-31 22:16:49 +0000492 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000493
adamdunkels35298692003-08-31 22:16:49 +0000494 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000495}
496/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000497/**
498 * Add a menu to the menu bar.
499 *
500 * \param menu The menu to be added.
501 *
502 * \note Do not call this function multiple times for the same menu,
503 * as no check is made to see if the menu already is in the menu bar.
504 */
505/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000506void
507ctk_menu_add(struct ctk_menu *menu)
508{
509#if CTK_CONF_MENUS
510 struct ctk_menu *m;
511
512 if(lastmenu == NULL) {
513 lastmenu = menu;
514 }
515
516 for(m = menus.menus; m->next != NULL; m = m->next) {
517 if(m == menu) {
518 return;
519 }
520 }
521 m->next = menu;
522 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000523
524 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000525#endif /* CTK_CONF_MENUS */
526}
527/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000528/**
529 * Remove a menu from the menu bar.
530 *
531 * \param menu The menu to be removed.
532 */
533/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000534void
535ctk_menu_remove(struct ctk_menu *menu)
536{
537#if CTK_CONF_MENUS
538 struct ctk_menu *m;
539
540 for(m = menus.menus; m->next != NULL; m = m->next) {
541 if(m->next == menu) {
542 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000543 if(menu == lastmenu) {
544 lastmenu = NULL;
545 }
546 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000547 return;
548 }
549 }
550#endif /* CTK_CONF_MENUS */
551}
552/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000553/**
554 * \internal Redraws everything on the screen within the clip
555 * interval.
556 *
557 * \param clipy1 The upper bound of the clip interval
558 * \param clipy2 The lower bound of the clip interval
559 */
560/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000561static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000562do_redraw_all(unsigned char clipy1, unsigned char clipy2)
563{
564 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000565 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000566
567 if(mode != CTK_MODE_NORMAL &&
568 mode != CTK_MODE_WINDOWMOVE) {
569 return;
570 }
571
572 ctk_draw_clear(clipy1, clipy2);
573
574 /* Draw widgets in root window */
575 for(widget = desktop_window.active;
576 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000577 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000578 }
579
580 /* Draw windows */
581 if(windows != NULL) {
582 /* Find the last window.*/
583 for(w = windows; w->next != NULL; w = w->next);
584
585 /* Draw the windows from back to front. */
586 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000587 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000588 ctk_draw_window(w, 0, clipy1, clipy2);
589 }
590 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000591 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000592 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
593 }
594
595 /* Draw dialog (if any) */
596 if(dialog != NULL) {
597 ctk_draw_dialog(dialog);
598 }
599
600#if CTK_CONF_MENUS
601 ctk_draw_menus(&menus);
602#endif /* CTK_CONF_MENUS */
603}
604/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000605/**
606 * Redraw the entire desktop.
607 *
608 * \param d The desktop to be redrawn.
609 *
610 * \note Currently the parameter d is not used, but must be set to
611 * NULL.
adamdunkelse937ded2003-10-01 07:53:57 +0000612 *
adamdunkels35298692003-08-31 22:16:49 +0000613 */
614/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000615void
adamdunkels965e2922003-06-30 20:44:57 +0000616ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000617{
618 if(DISPATCHER_CURRENT() == ctkid) {
619 if(mode == CTK_MODE_NORMAL ||
620 mode == CTK_MODE_WINDOWMOVE) {
621 do_redraw_all(1, height);
622 }
623 } else {
624 redraw |= REDRAW_ALL;
625 }
626}
627/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000628/**
629 * Redraw a window.
630 *
631 * This function redraws the window, but only if it is the foremost
632 * one on the desktop.
633 *
634 * \param w The window to be redrawn.
635 */
636/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000637void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000638ctk_window_redraw(struct ctk_window *w)
639{
640 /* Only redraw the window if it is a dialog or if it is the foremost
641 window. */
642 if(mode != CTK_MODE_NORMAL) {
643 return;
644 }
645
646 if(w == dialog) {
647 ctk_draw_dialog(w);
648 } else if(dialog == NULL &&
649#if CTK_CONF_MENUS
650 menus.open == NULL &&
651#endif /* CTK_CONF_MENUS */
652 windows == w) {
653 ctk_draw_window(w, CTK_FOCUS_WINDOW,
654 0, height);
655 }
656}
657/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000658/**
659 * \internal Creates a new window.
660 *
661 * \param window The window to be created.
662 * \param w The width of the window.
663 * \param h The height of the window.
664 * \param title The title of the window.
665 */
666/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000667static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000668window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000669 unsigned char w, unsigned char h,
670 char *title)
671{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000672
673 if(w >= width - 2) {
674 window->x = 0;
675 } else {
676 window->x = (width - w - 2) / 2;
677 }
678 if(h >= height - 3) {
679 window->y = 0;
680 } else {
681 window->y = (height - h - 1) / 2;
682 }
683
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000684 window->w = w;
685 window->h = h;
686 window->title = title;
687 if(title != NULL) {
688 window->titlelen = strlen(title);
689 } else {
690 window->titlelen = 0;
691 }
692 window->next = window->prev = NULL;
693 window->owner = DISPATCHER_CURRENT();
694 window->active = window->inactive = window->focused = NULL;
695}
696/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000697/**
698 * Create a new window.
699 *
700 * Creates a new window. The memory for the window structure must
701 * already be allocated by the caller, and is usually done with a
702 * static declaration.
703 *
704 * This function sets up the internal structure of the ctk_window
705 * struct and creates the move and close buttons, but it does not open
706 * the window. The window must be explicitly opened by calling the
707 * ctk_window_open() function.
708 *
709 * \param window The window to be created.
710 * \param w The width of the new window.
711 * \param h The height of the new window.
712 * \param title The title of the new window.
713 */
714/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000715void
716ctk_window_new(struct ctk_window *window,
717 unsigned char w, unsigned char h,
718 char *title)
719{
720 window_new(window, w, h, title);
721
722 make_windowbuttons(window);
723}
724/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000725/**
726 * Creates a new dialog.
727 *
728 * This function only sets up the internal structure of the ctk_window
729 * struct but does not open the dialog. The dialog must be explicitly
730 * opened by calling the ctk_dialog_open() function.
731 *
732 * \param dialog The dialog to be created.
733 * \param w The width of the dialog.
734 * \param h The height of the dialog.
735 */
736/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000737void
adamdunkels35298692003-08-31 22:16:49 +0000738ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000739 unsigned char w, unsigned char h)
740{
adamdunkels35298692003-08-31 22:16:49 +0000741 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000742}
adamdunkels3af580f2003-08-11 22:27:13 +0000743/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000744/**
745 * Creates a new menu.
746 *
747 * This function sets up the internal structure of the menu, but does
748 * not add it to the menubar. Use the function ctk_menu_add() for that
749 * purpose.
750 *
751 * \param menu The menu to be created.
752 * \param title The title of the menu.
753 */
754/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000755void
adamdunkelsd07a5422003-04-05 12:22:35 +0000756ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000757 char *title)
758{
759#if CTK_CONF_MENUS
760 menu->next = NULL;
761 menu->title = title;
762 menu->titlelen = strlen(title);
763 menu->active = 0;
764 menu->nitems = 0;
765#endif /* CTK_CONF_MENUS */
766}
767/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000768/**
769 * Adds a menu item to a menu.
770 *
771 * In CTK, each menu item is identified by a number which is unique
772 * within each menu. When a menu item is selected, a
773 * ctk_menuitem_activated signal is emitted and the menu item number
774 * is passed as signal data with the signal.
775 *
776 * \param menu The menu to which the menu item should be added.
777 * \param name The name of the menu item.
778 * \return The number of the menu item.
779 */
780/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000782ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000783 char *name)
784{
785#if CTK_CONF_MENUS
786 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
787 return 0;
788 }
789 menu->items[menu->nitems].title = name;
790 menu->items[menu->nitems].titlelen = strlen(name);
791 return menu->nitems++;
792#else
793 return 0;
794#endif /* CTK_CONF_MENUS */
795}
796/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000797/**
798 * \internal Adds a widget to the list of widgets that should be
799 * redrawn.
800 *
801 * \param w The widget that should be redrawn.
802 */
803/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000804static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805add_redrawwidget(struct ctk_widget *w)
806{
807 static unsigned char i;
808
809 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
810 redraw |= REDRAW_FOCUS;
811 } else {
812 redraw |= REDRAW_WIDGETS;
813 /* Check if it is in the queue already. If so, we don't add it
814 again. */
815 for(i = 0; i < redraw_widgetptr; ++i) {
816 if(redraw_widgets[i] == w) {
817 return;
818 }
819 }
820 redraw_widgets[redraw_widgetptr++] = w;
821 }
822}
823/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000824/**
825 * \internal Checks if a widget redrawn and adds it to the list of
826 * widgets to be redrawn.
827 *
828 * A widget can be redrawn only if the current CTK mode is
829 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
830 * foremost window.
831 *
832 * \param widget The widget that should be redrawn.
833 */
834/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000835static void
836widget_redraw(struct ctk_widget *widget)
837{
838 struct ctk_window *window;
839
840 if(mode != CTK_MODE_NORMAL || widget == NULL) {
841 return;
842 }
843
844 /* Only redraw widgets that are in the foremost window. If we would
845 allow redrawing widgets in non-focused windows, we would have to
846 redraw all the windows that cover the non-focused window as well,
847 which would lead to flickering.
848
849 Also, we avoid drawing any widgets when the menus are active.
850 */
851
852#if CTK_CONF_MENUS
853 if(menus.open == NULL)
854#endif /* CTK_CONF_MENUS */
855 {
856 window = widget->window;
857 if(window == dialog) {
858 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
859 } else if(dialog == NULL &&
860 (window == windows ||
861 window == &desktop_window)) {
862 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
863 }
864 }
865}
866/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000867/**
868 * Redraws a widget.
869 *
870 * This function will set a flag which causes the widget to be redrawn
871 * next time the CTK process is scheduled.
872 *
873 * \param widget The widget that is to be redrawn.
874 *
875 * \note This function should usually not be called directly since it
876 * requires typecasting of the widget parameter. The wrapper macro
877 * CTK_WIDGET_REDRAW() does the required typecast and should be used
878 * instead.
879 */
880/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000881void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882ctk_widget_redraw(struct ctk_widget *widget)
883{
adamdunkels9f667f22003-04-16 18:29:19 +0000884 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000885 return;
886 }
887
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000888 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000889 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000890 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000891}
892/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000893/**
894 * Adds a widget to a window.
895 *
896 * This function adds a widget to a window. The order of which the
897 * widgets are added is important, as it sets the order to which
898 * widgets are cycled with the widget selection keys.
899 *
900 * \param window The window to which the widhet should be added.
901 * \param widget The widget to be added.
902 */
903/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000904void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000905ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
906 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000907{
908 if(widget->type == CTK_WIDGET_LABEL ||
909 widget->type == CTK_WIDGET_SEPARATOR) {
910 widget->next = window->inactive;
911 window->inactive = widget;
912 widget->window = window;
913 } else {
914 widget->next = window->active;
915 window->active = widget;
916 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000917 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000918 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000919 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000920 }
921}
922/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000923/**
924 * Gets the width of the desktop.
925 *
926 * \param d The desktop.
927 * \return The width of the desktop, in characters.
928 *
929 * \note The d parameter is currently unused and must be set to NULL.
930 */
931/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000932unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000933ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000934{
935 return ctk_draw_width();
936}
937/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000938/**
939 * Gets the height of the desktop.
940 *
941 * \param d The desktop.
942 * \return The height of the desktop, in characters.
943 *
944 * \note The d parameter is currently unused and must be set to NULL.
945 */
946/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000947unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000948ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000949{
950 return ctk_draw_height();
951}
952/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000953/**
954 * \internal Selects a widget in the window of the widget.
955 *
956 * \param focus The widget to be focused.
957 */
958/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000959static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000960select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000961{
962 struct ctk_window *window;
963
964 window = focus->window;
965
966 if(focus != window->focused) {
967 window->focused = focus;
968 /* The operation changed the focus, so we emit a "hover" signal
969 for those widgets that support it. */
970
971 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
972 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
973 window->owner);
974 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
975 dispatcher_emit(ctk_signal_button_hover, window->focused,
976 window->owner);
977 }
978
979 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000980
981 dispatcher_emit(ctk_signal_widget_select, focus,
982 focus->window->owner);
983
adamdunkelse0683312003-04-09 09:02:52 +0000984 }
985
986}
987/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000988#define UP 0
989#define DOWN 1
990#define LEFT 2
991#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000992static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000993switch_focus_widget(unsigned char direction)
994{
995 register struct ctk_window *window;
996 register struct ctk_widget *focus;
997 struct ctk_widget *widget;
998
999
1000 if(dialog != NULL) {
1001 window = dialog;
1002 } else {
1003 window = windows;
1004 }
1005
1006 /* If there are no windows open, we move focus around between the
1007 icons on the root window instead. */
1008 if(window == NULL) {
1009 window = &desktop_window;
1010 }
1011
1012 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +00001013 if(focus == NULL) {
1014 focus = window->active;
1015 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001016 add_redrawwidget(focus);
1017
1018 if((direction & 1) == 0) {
1019 /* Move focus "up" */
1020 focus = focus->next;
1021 } else {
1022 /* Move focus "down" */
1023 for(widget = window->active;
1024 widget != NULL; widget = widget->next) {
1025 if(widget->next == focus) {
1026 break;
1027 }
1028 }
1029 focus = widget;
1030 if(focus == NULL) {
1031 if(window->active != NULL) {
1032 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001033 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001034 }
1035 }
1036 }
1037 if(focus == NULL) {
1038 focus = window->active;
1039 }
adamdunkelse0683312003-04-09 09:02:52 +00001040
adamdunkelsb2486562003-04-11 20:22:03 +00001041 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001042}
1043/*-----------------------------------------------------------------------------------*/
1044#if CTK_CONF_MENUS
1045static void
1046switch_open_menu(unsigned char rightleft)
1047{
1048 struct ctk_menu *menu;
1049
1050 if(rightleft == 0) {
1051 /* Move right */
1052 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1053 if(menu->next == menus.open) {
1054 break;
1055 }
1056 }
1057 lastmenu = menus.open;
1058 menus.open = menu;
1059 if(menus.open == NULL) {
1060 for(menu = menus.menus;
1061 menu->next != NULL; menu = menu->next);
1062 menus.open = menu;
1063 }
1064 } else {
1065 /* Move to left */
1066 lastmenu = menus.open;
1067 menus.open = menus.open->next;
1068 if(menus.open == NULL) {
1069 menus.open = menus.menus;
1070 }
1071 }
1072
adamdunkels66109622003-04-24 17:17:10 +00001073 menus.open->active = 0;
1074
1075 /* if(menus.open->nitems > maxnitems) {
1076 maxnitems = menus.open->nitems;
1077 }*/
1078
adamdunkels965e2922003-06-30 20:44:57 +00001079 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001080}
1081/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001082static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001083switch_menu_item(unsigned char updown)
1084{
1085 register struct ctk_menu *m;
1086
1087 m = menus.open;
1088
1089 if(updown == 0) {
1090 /* Move up */
1091 if(m->active == 0) {
1092 m->active = m->nitems - 1;
1093 } else {
1094 --m->active;
1095 if(m->items[m->active].title[0] == '-') {
1096 --m->active;
1097 }
1098 }
1099 } else {
1100 /* Move down */
1101 if(m->active >= m->nitems - 1) {
1102 m->active = 0;
1103 } else {
1104 ++m->active;
1105 if(m->items[m->active].title[0] == '-') {
1106 ++m->active;
1107 }
1108 }
1109 }
1110
1111}
1112#endif /* CTK_CONF_MENUS */
1113/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001114static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001115activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001116{
1117 static unsigned char len;
1118
1119 if(w->type == CTK_WIDGET_BUTTON) {
1120 if(w == (struct ctk_widget *)&windows->closebutton) {
1121#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +00001122 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001123 ctk_window_close(windows);
1124 return REDRAW_ALL;
1125#endif /* CTK_CONF_WINDOWCLOSE */
1126 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1127#if CTK_CONF_WINDOWCLOSE
1128 mode = CTK_MODE_WINDOWMOVE;
1129#endif /* CTK_CONF_WINDOWCLOSE */
1130 } else {
adamdunkels58917a82003-04-18 00:18:38 +00001131 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001132 w->window->owner);
1133 }
1134#if CTK_CONF_ICONS
1135 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +00001136 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001137 w->widget.icon.owner);
1138#endif /* CTK_CONF_ICONS */
1139 } else if(w->type == CTK_WIDGET_HYPERLINK) {
1140 dispatcher_emit(ctk_signal_hyperlink_activate, w,
1141 DISPATCHER_BROADCAST);
1142 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1143 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1144 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1145 len = strlen(w->widget.textentry.text);
1146 if(w->widget.textentry.xpos > len) {
1147 w->widget.textentry.xpos = len;
1148 }
1149 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1150 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +00001151 dispatcher_emit(ctk_signal_widget_activate, w,
1152 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001153 }
1154 add_redrawwidget(w);
1155 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001156 } else {
1157 dispatcher_emit(ctk_signal_widget_activate, w,
1158 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001159 }
1160 return REDRAW_NONE;
1161}
1162/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001163static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001164textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001165 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001166{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001167 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001168 static unsigned char len, txpos, typos, tlen;
1169
1170 txpos = t->xpos;
1171 typos = t->ypos;
1172 tlen = t->len;
1173
1174 cptr = &t->text[txpos + typos * tlen];
1175
1176 switch(c) {
1177 case CH_CURS_LEFT:
1178 if(txpos > 0) {
1179 --txpos;
1180 }
1181 break;
1182
1183 case CH_CURS_RIGHT:
1184 if(txpos < tlen &&
1185 *cptr != 0) {
1186 ++txpos;
1187 }
1188 break;
1189
1190 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001191 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001192 break;
1193
1194 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001195 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001196 break;
1197
1198 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001199 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1200 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001201 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001202 break;
1203
adamdunkels9795b2e2003-08-09 23:32:37 +00001204 case CTK_CONF_WIDGETDOWN_KEY:
1205 t->state = CTK_TEXTENTRY_NORMAL;
1206 switch_focus_widget(DOWN);
1207 break;
1208 case CTK_CONF_WIDGETUP_KEY:
1209 t->state = CTK_TEXTENTRY_NORMAL;
1210 switch_focus_widget(UP);
1211 break;
1212
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001213 default:
1214 len = tlen - txpos - 1;
1215 if(c == CH_DEL) {
1216 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +00001217 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 *(cptr + len - 1) = 0;
1219 --txpos;
1220 }
1221 } else {
1222 if(len > 0) {
1223 cptr2 = cptr + len - 1;
1224 while(cptr2 + 1 > cptr) {
1225 *(cptr2 + 1) = *cptr2;
1226 --cptr2;
1227 }
1228
1229 *cptr = c;
1230 ++txpos;
1231 }
1232 }
1233 break;
1234 }
1235
1236 t->xpos = txpos;
1237 t->ypos = typos;
1238}
1239/*-----------------------------------------------------------------------------------*/
1240#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001241static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001242activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001243{
1244 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001245
adamdunkelsb2486562003-04-11 20:22:03 +00001246 lastmenu = menus.open;
1247 if(menus.open == &desktopmenu) {
1248 for(w = windows; w != NULL; w = w->next) {
1249 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1250 ctk_window_open(w);
1251 menus.open = NULL;
1252 return REDRAW_ALL;
1253 }
1254 }
1255 } else {
1256 dispatcher_emit(ctk_signal_menu_activate, menus.open,
1257 DISPATCHER_BROADCAST);
1258 }
1259 menus.open = NULL;
1260 return REDRAW_MENUPART;
1261}
1262/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001263static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001264menus_input(ctk_arch_key_t c)
1265{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266
1267 if(menus.open->nitems > maxnitems) {
1268 maxnitems = menus.open->nitems;
1269 }
1270
1271
1272 switch(c) {
1273 case CH_CURS_RIGHT:
1274 switch_open_menu(1);
1275
1276 return REDRAW_MENUPART;
1277
1278 case CH_CURS_DOWN:
1279 switch_menu_item(1);
1280 return REDRAW_MENUS;
1281
1282 case CH_CURS_LEFT:
1283 switch_open_menu(0);
1284 return REDRAW_MENUPART;
1285
1286 case CH_CURS_UP:
1287 switch_menu_item(0);
1288 return REDRAW_MENUS;
1289
1290 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001291 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001292
adamdunkels88ed9c42003-03-28 12:10:09 +00001293 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001294 lastmenu = menus.open;
1295 menus.open = NULL;
1296 return REDRAW_MENUPART;
1297 }
adamdunkelsb2486562003-04-11 20:22:03 +00001298
1299 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001300}
1301#endif /* CTK_CONF_MENUS */
1302/*-----------------------------------------------------------------------------------*/
1303static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001304timer(void)
1305{
1306 if(mode == CTK_MODE_NORMAL) {
1307 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001308 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001309#if CTK_CONF_SCREENSAVER
1310 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1311 DISPATCHER_BROADCAST);
1312#ifdef CTK_SCREENSAVER_INIT
1313 CTK_SCREENSAVER_INIT();
1314#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001315
adamdunkelscf90b0d2003-08-09 13:34:16 +00001316#endif /* CTK_CONF_SCREENSAVER */
1317 screensaver_timer = 0;
1318 }
1319 }
1320}
1321/*-----------------------------------------------------------------------------------*/
1322static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001323unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1324{
1325 if(w != NULL) {
1326 redraw |= REDRAW_WIDGETS;
1327 add_redrawwidget(w);
1328 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1329 ((struct ctk_textentry *)w)->state =
1330 CTK_TEXTENTRY_NORMAL;
1331 }
1332 w->window->focused = NULL;
1333 }
1334}
1335/*-----------------------------------------------------------------------------------*/
1336static void
adamdunkelsc4902862003-04-09 00:30:45 +00001337ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001338{
1339 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001340 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001341 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001342 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001343 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001344#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001345 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1346 mouse_clicked;
1347 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001348 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001349
adamdunkels19a787c2003-04-09 09:22:24 +00001350#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001351
1352
1353 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001354
adamdunkels9795b2e2003-08-09 23:32:37 +00001355 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001356 timer();
1357 start = current;
1358 }
1359
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001360#if CTK_CONF_MENUS
1361 if(menus.open != NULL) {
1362 maxnitems = menus.open->nitems;
1363 } else {
1364 maxnitems = 0;
1365 }
1366#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001367
1368#if CTK_CONF_MOUSE_SUPPORT
1369 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1370
1371 /* See if there is any change in the buttons. */
1372 if(ctk_mouse_button() != mouse_button) {
1373 mouse_button = ctk_mouse_button();
1374 mouse_button_changed = 1;
1375 if(mouse_button == 0) {
1376 mouse_clicked = 1;
1377 }
1378 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001379
adamdunkelsb2486562003-04-11 20:22:03 +00001380 /* Check if the mouse pointer has moved. */
1381 if(ctk_mouse_x() != mouse_x ||
1382 ctk_mouse_y() != mouse_y) {
1383 mouse_x = ctk_mouse_x();
1384 mouse_y = ctk_mouse_y();
1385 mouse_moved = 1;
1386 }
1387
1388 mxc = ctk_mouse_xtoc(mouse_x);
1389 myc = ctk_mouse_ytoc(mouse_y);
1390#endif /* CTK_CONF_MOUSE_SUPPORT */
1391
1392
adamdunkels66109622003-04-24 17:17:10 +00001393#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001394 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001395 if(ctk_arch_keyavail()
1396#if CTK_CONF_MOUSE_SUPPORT
1397 || mouse_moved || mouse_button_changed
1398#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001399 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001400 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1401 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001402 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001403 }
adamdunkels66109622003-04-24 17:17:10 +00001404 } else
1405#endif /* CTK_CONF_SCREENSAVER */
1406 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001407#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001408 /* If there is any change in the mouse conditions, find out in
1409 which window the mouse pointer currently is in order to send
1410 the correct signals, or bring a window to focus. */
1411 if(mouse_moved || mouse_button_changed) {
1412 ctk_mouse_show();
1413 screensaver_timer = 0;
1414
1415 if(myc == 0) {
1416 /* Here we should do whatever needs to be done when the mouse
1417 moves around and clicks in the menubar. */
1418 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001419 static unsigned char titlelen;
1420
adamdunkelsb2486562003-04-11 20:22:03 +00001421 /* Find out which menu that the mouse pointer is in. Start
1422 with the ->next menu after the desktop menu. We assume
1423 that the menus start one character from the left screen
1424 side and that the desktop menu is farthest to the
1425 right. */
1426 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001427 for(menu = menus.menus->next;
1428 menu != NULL; menu = menu->next) {
1429 titlelen = menu->titlelen;
1430 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001431 break;
adamdunkelse0683312003-04-09 09:02:52 +00001432 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001433 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001434 }
adamdunkelsb2486562003-04-11 20:22:03 +00001435
1436 /* Also check desktop menu. */
1437 if(mxc >= width - 7 &&
1438 mxc <= width - 1) {
1439 menu = &desktopmenu;
1440 }
1441
1442 menus.open = menu;
1443 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001444 }
adamdunkelse0683312003-04-09 09:02:52 +00001445 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001446 --myc;
1447
1448 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001449 static unsigned char nitems;
1450
adamdunkelsb2486562003-04-11 20:22:03 +00001451 /* Do whatever needs to be done when a menu is open. */
1452
adamdunkelscf90b0d2003-08-09 13:34:16 +00001453 /* First check if the mouse pointer is in the currently open
1454 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001455 if(menus.open == &desktopmenu) {
1456 menux = width - CTK_CONF_MENUWIDTH;
1457 } else {
1458 menux = 1;
1459 for(menu = menus.menus->next; menu != menus.open;
1460 menu = menu->next) {
1461 menux += menu->titlelen;
1462 }
1463 }
1464
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001465 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001466 /* Find out which of the menu items the mouse is pointing
1467 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001468 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1469 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001470 menus.open->active = myc;
1471 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001472 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001473 }
adamdunkelsb2486562003-04-11 20:22:03 +00001474 }
1475
1476 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001477 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001478 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001479 redraw |= activate_menu();
1480 } else {
1481 lastmenu = menus.open;
1482 menus.open = NULL;
1483 redraw |= REDRAW_MENUPART;
1484 }
1485 } else {
1486 redraw |= REDRAW_MENUS;
1487 }
1488 } else {
1489
adamdunkels965e2922003-06-30 20:44:57 +00001490 /* Walk through the windows from top to bottom to see in
1491 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001492 if(dialog != NULL) {
1493 window = dialog;
1494 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001495 for(window = windows; window != NULL;
1496 window = window->next) {
1497
adamdunkelsb2486562003-04-11 20:22:03 +00001498 /* Check if the mouse is within the window. */
1499 if(mxc >= window->x &&
1500 mxc <= window->x + window->w &&
1501 myc >= window->y &&
1502 myc <= window->y + window->h) {
1503 break;
1504 }
1505 }
1506 }
1507
1508
1509 /* If we didn't find any window, and there are no windows
1510 open, the mouse pointer will definately be within the
1511 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001512 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001513 window = &desktop_window;
1514 }
1515
adamdunkels965e2922003-06-30 20:44:57 +00001516 /* If the mouse pointer moves around outside of the
1517 currently focused window (or dialog), we should not have
1518 any focused widgets in the focused window so we make sure
1519 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001520 if(windows != NULL &&
1521 window != windows &&
1522 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001523 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001524 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001525 redraw |= REDRAW_WIDGETS;*/
1526 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001527 }
1528
1529 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001530 /* If the mouse was clicked outside of the current window,
1531 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001532 if(dialog == NULL &&
1533 window != &desktop_window &&
1534 window != windows &&
1535 mouse_clicked) {
1536 /* Bring window to front. */
1537 ctk_window_open(window);
1538 redraw |= REDRAW_ALL;
1539 } else {
1540
adamdunkels965e2922003-06-30 20:44:57 +00001541 /* Find out which widget currently is under the mouse
1542 pointer and give it focus, unless it already has
1543 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001544 mxc = mxc - window->x - 1;
1545 myc = myc - window->y - 1;
1546
adamdunkels965e2922003-06-30 20:44:57 +00001547 /* See if the mouse pointer is on a widget. If so, it
1548 should be selected and, if the button is clicked,
1549 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001550 for(widget = window->active; widget != NULL;
1551 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552
adamdunkelsb2486562003-04-11 20:22:03 +00001553 if(mxc >= widget->x &&
1554 mxc <= widget->x + widget->w &&
1555 (myc == widget->y ||
1556 ((widget->type == CTK_WIDGET_BITMAP ||
1557 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1558 widget->type == CTK_WIDGET_ICON) &&
1559 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001560 myc <= widget->y +
1561 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001562 break;
1563 }
1564 }
1565
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001566
1567 /* if the mouse is moved in the focused window, we emit
1568 a ctk_signal_pointer_move signal to the owner of the
1569 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001570 if(mouse_moved &&
1571 (window != &desktop_window ||
1572 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001573
adamdunkelsb2486562003-04-11 20:22:03 +00001574 dispatcher_emit(ctk_signal_pointer_move, NULL,
1575 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001576
1577 /* If there was a focused widget that is not below the
1578 mouse pointer, we remove focus from the widget and
1579 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001580 if(window->focused != NULL &&
1581 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001582 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001583 if(CTK_WIDGET_TYPE(window->focused) ==
1584 CTK_WIDGET_TEXTENTRY) {
1585 ((struct ctk_textentry *)(window->focused))->state =
1586 CTK_TEXTENTRY_NORMAL;
1587 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001588 window->focused = NULL;*/
1589 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001590 }
1591 redraw |= REDRAW_WIDGETS;
1592 if(widget != NULL) {
1593 select_widget(widget);
1594 }
1595 }
1596
1597 if(mouse_button_changed) {
1598 dispatcher_emit(ctk_signal_pointer_button,
1599 (ek_data_t)mouse_button,
1600 window->owner);
1601 if(mouse_clicked && widget != NULL) {
1602 select_widget(widget);
1603 redraw |= activate(widget);
1604 }
1605 }
1606 }
1607 }
1608 }
adamdunkelsc4902862003-04-09 00:30:45 +00001609 }
1610 }
adamdunkels19a787c2003-04-09 09:22:24 +00001611#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001612
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001613 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001614
1615 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001616
1617 screensaver_timer = 0;
1618
adamdunkelsb2486562003-04-11 20:22:03 +00001619 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001620
1621 if(dialog != NULL) {
1622 window = dialog;
1623 } else if(windows != NULL) {
1624 window = windows;
1625 } else {
1626 window = &desktop_window;
1627 }
1628 widget = window->focused;
1629
1630
1631 if(widget != NULL &&
1632 widget->type == CTK_WIDGET_TEXTENTRY &&
1633 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1634 textentry_input(c, (struct ctk_textentry *)widget);
1635 add_redrawwidget(widget);
1636#if CTK_CONF_MENUS
1637 } else if(menus.open != NULL) {
1638 redraw |= menus_input(c);
1639#endif /* CTK_CONF_MENUS */
1640 } else {
1641 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001642 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001643 switch_focus_widget(DOWN);
1644 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001645 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001646 switch_focus_widget(UP);
1647 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001648#if CTK_CONF_MENUS
1649 case CTK_CONF_MENU_KEY:
1650 if(dialog == NULL) {
1651 if(lastmenu == NULL) {
1652 menus.open = menus.menus;
1653 } else {
1654 menus.open = lastmenu;
1655 }
1656 menus.open->active = 0;
1657 redraw |= REDRAW_MENUS;
1658 }
1659 break;
1660#endif /* CTK_CONF_MENUS */
1661 case CTK_CONF_WINDOWSWITCH_KEY:
1662 if(windows != NULL) {
1663 for(window = windows; window->next != NULL;
1664 window = window->next);
1665 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001666 }
1667 break;
1668 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001669 if(c == CH_ENTER &&
1670 widget != NULL) {
1671 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001672 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001673 if(widget != NULL &&
1674 widget->type == CTK_WIDGET_TEXTENTRY) {
1675 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1676 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001677 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001678 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001679 /* window->focused = NULL;*/
1680 unfocus_widget(window->focused);
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001681 dispatcher_fastemit(ctk_signal_keypress, (void *)c,
1682 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001683 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001684 }
1685 break;
1686 }
1687 }
1688
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001689#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001690 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001691 widgetptr = redraw_widgets;
1692 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001693 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001694 *widgetptr = NULL;
1695 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001696 }
1697 redraw &= ~REDRAW_WIDGETS;
1698 redraw_widgetptr = 0;
1699 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001700#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001701 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001702#if CTK_CONF_WINDOWMOVE
1703 } else if(mode == CTK_MODE_WINDOWMOVE) {
1704
1705 redraw = 0;
1706
1707 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001708
1709#if CTK_CONF_MOUSE_SUPPORT
1710
1711 /* If the mouse has moved, we move the window as well. */
1712 if(mouse_moved) {
1713
1714 if(window->w + mxc + 2 >= width) {
1715 window->x = width - 2 - window->w;
1716 } else {
1717 window->x = mxc;
1718 }
1719
1720 if(window->h + myc + 2 >= height) {
1721 window->y = height - 2 - window->h;
1722 } else {
1723 window->y = myc;
1724 }
1725 if(window->y > 0) {
1726 --window->y;
1727 }
1728
1729 redraw = REDRAW_ALL;
1730 }
1731
1732 /* Check if the mouse has been clicked, and stop moving the window
1733 if so. */
1734 if(mouse_button_changed &&
1735 mouse_button == 0) {
1736 mode = CTK_MODE_NORMAL;
1737 redraw = REDRAW_ALL;
1738 }
1739#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001740
1741 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1742
1743 screensaver_timer = 0;
1744
1745 c = ctk_arch_getkey();
1746
1747 switch(c) {
1748 case CH_CURS_RIGHT:
1749 ++window->x;
1750 if(window->x + window->w + 1 >= width) {
1751 --window->x;
1752 }
1753 redraw = REDRAW_ALL;
1754 break;
1755 case CH_CURS_LEFT:
1756 if(window->x > 0) {
1757 --window->x;
1758 }
1759 redraw = REDRAW_ALL;
1760 break;
1761 case CH_CURS_DOWN:
1762 ++window->y;
1763 if(window->y + window->h + 2 >= height) {
1764 --window->y;
1765 }
1766 redraw = REDRAW_ALL;
1767 break;
1768 case CH_CURS_UP:
1769 if(window->y > 0) {
1770 --window->y;
1771 }
1772 redraw = REDRAW_ALL;
1773 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001774 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001775 mode = CTK_MODE_NORMAL;
1776 redraw = REDRAW_ALL;
1777 break;
1778 }
1779 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001780#endif /* CTK_CONF_WINDOWMOVE */
1781 }
adamdunkelsb2486562003-04-11 20:22:03 +00001782
1783 if(redraw & REDRAW_ALL) {
1784 do_redraw_all(1, height);
1785#if CTK_CONF_MENUS
1786 } else if(redraw & REDRAW_MENUPART) {
1787 do_redraw_all(1, maxnitems + 1);
1788 } else if(redraw & REDRAW_MENUS) {
1789 ctk_draw_menus(&menus);
1790#endif /* CTK_CONF_MENUS */
1791 } else if(redraw & REDRAW_FOCUS) {
1792 if(dialog != NULL) {
1793 ctk_window_redraw(dialog);
1794 } else if(windows != NULL) {
1795 ctk_window_redraw(windows);
1796 } else {
1797 ctk_window_redraw(&desktop_window);
1798 }
1799 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001800 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001801 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001802 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001803 *widgetptr = NULL;
1804 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001805 }
1806 }
1807 redraw = 0;
1808 redraw_widgetptr = 0;
1809
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001810}
1811/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001812/** @} */
1813/** @} */
1814