blob: baed927217864887994de8b3673940d5fa0c8bca [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 *
oliverschmidtf42b7bc2004-06-27 15:04:01 +000046 * $Id: ctk.c,v 1.38 2004/06/27 15:04:01 oliverschmidt 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) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000577 ctk_draw_widget(widget, windows != NULL? 0: 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:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001184 if(txpos < tlen - 1 && *cptr != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001185 ++txpos;
1186 }
1187 break;
1188
1189 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001190 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001191 break;
1192
1193 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001194 txpos = strlen(t->text);
oliverschmidtd52d46c2004-06-14 22:11:01 +00001195 if(txpos == tlen) {
1196 --txpos;
1197 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001198 break;
1199
1200 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001201 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1202 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001203 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001204 break;
1205
adamdunkels9795b2e2003-08-09 23:32:37 +00001206 case CTK_CONF_WIDGETDOWN_KEY:
1207 t->state = CTK_TEXTENTRY_NORMAL;
1208 switch_focus_widget(DOWN);
1209 break;
1210 case CTK_CONF_WIDGETUP_KEY:
1211 t->state = CTK_TEXTENTRY_NORMAL;
1212 switch_focus_widget(UP);
1213 break;
1214
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001215 default:
oliverschmidtd52d46c2004-06-14 22:11:01 +00001216 len = tlen - txpos;
1217 if(c == CH_DEL) {
1218 if(len == 1 && *cptr != 0) {
1219 *cptr = 0;
adamdunkelsc9619082004-06-06 06:19:25 +00001220 } else {
oliverschmidtd52d46c2004-06-14 22:11:01 +00001221 if(txpos > 0) {
1222 --txpos;
1223 strcpy(cptr - 1, cptr);
1224 }
1225 }
1226 } else {
1227 if(ctk_arch_isprint(c)) {
1228 if(len > 1) {
adamdunkelsc9619082004-06-06 06:19:25 +00001229 cptr2 = cptr + len - 1;
oliverschmidtd52d46c2004-06-14 22:11:01 +00001230 while(cptr2 > cptr) {
1231 *cptr2 = *(cptr2 - 1);
adamdunkelsc9619082004-06-06 06:19:25 +00001232 --cptr2;
1233 }
adamdunkelsc9619082004-06-06 06:19:25 +00001234 ++txpos;
1235 }
oliverschmidtd52d46c2004-06-14 22:11:01 +00001236 *cptr = c;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001237 }
1238 }
1239 break;
1240 }
1241
1242 t->xpos = txpos;
1243 t->ypos = typos;
1244}
1245/*-----------------------------------------------------------------------------------*/
1246#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001247static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001248activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001249{
1250 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001251
adamdunkelsb2486562003-04-11 20:22:03 +00001252 lastmenu = menus.open;
1253 if(menus.open == &desktopmenu) {
1254 for(w = windows; w != NULL; w = w->next) {
1255 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1256 ctk_window_open(w);
1257 menus.open = NULL;
1258 return REDRAW_ALL;
1259 }
1260 }
1261 } else {
1262 dispatcher_emit(ctk_signal_menu_activate, menus.open,
1263 DISPATCHER_BROADCAST);
1264 }
1265 menus.open = NULL;
1266 return REDRAW_MENUPART;
1267}
1268/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001269static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001270menus_input(ctk_arch_key_t c)
1271{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272
1273 if(menus.open->nitems > maxnitems) {
1274 maxnitems = menus.open->nitems;
1275 }
1276
1277
1278 switch(c) {
1279 case CH_CURS_RIGHT:
1280 switch_open_menu(1);
1281
1282 return REDRAW_MENUPART;
1283
1284 case CH_CURS_DOWN:
1285 switch_menu_item(1);
1286 return REDRAW_MENUS;
1287
1288 case CH_CURS_LEFT:
1289 switch_open_menu(0);
1290 return REDRAW_MENUPART;
1291
1292 case CH_CURS_UP:
1293 switch_menu_item(0);
1294 return REDRAW_MENUS;
1295
1296 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001297 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001298
adamdunkels88ed9c42003-03-28 12:10:09 +00001299 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001300 lastmenu = menus.open;
1301 menus.open = NULL;
1302 return REDRAW_MENUPART;
1303 }
adamdunkelsb2486562003-04-11 20:22:03 +00001304
1305 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001306}
1307#endif /* CTK_CONF_MENUS */
1308/*-----------------------------------------------------------------------------------*/
1309static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001310timer(void)
1311{
1312 if(mode == CTK_MODE_NORMAL) {
1313 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001314 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001315#if CTK_CONF_SCREENSAVER
1316 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1317 DISPATCHER_BROADCAST);
1318#ifdef CTK_SCREENSAVER_INIT
1319 CTK_SCREENSAVER_INIT();
1320#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001321
adamdunkelscf90b0d2003-08-09 13:34:16 +00001322#endif /* CTK_CONF_SCREENSAVER */
1323 screensaver_timer = 0;
1324 }
1325 }
1326}
1327/*-----------------------------------------------------------------------------------*/
1328static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001329unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1330{
1331 if(w != NULL) {
1332 redraw |= REDRAW_WIDGETS;
1333 add_redrawwidget(w);
1334 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1335 ((struct ctk_textentry *)w)->state =
1336 CTK_TEXTENTRY_NORMAL;
1337 }
1338 w->window->focused = NULL;
1339 }
1340}
1341/*-----------------------------------------------------------------------------------*/
1342static void
adamdunkelsc4902862003-04-09 00:30:45 +00001343ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001344{
1345 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001346 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001347 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001348 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001349 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001350#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001351 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1352 mouse_clicked;
1353 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001354 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001355
adamdunkels19a787c2003-04-09 09:22:24 +00001356#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001357
1358
1359 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001360
adamdunkels9795b2e2003-08-09 23:32:37 +00001361 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001362 timer();
1363 start = current;
1364 }
1365
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001366#if CTK_CONF_MENUS
1367 if(menus.open != NULL) {
1368 maxnitems = menus.open->nitems;
1369 } else {
1370 maxnitems = 0;
1371 }
1372#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001373
1374#if CTK_CONF_MOUSE_SUPPORT
1375 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1376
1377 /* See if there is any change in the buttons. */
1378 if(ctk_mouse_button() != mouse_button) {
1379 mouse_button = ctk_mouse_button();
1380 mouse_button_changed = 1;
1381 if(mouse_button == 0) {
1382 mouse_clicked = 1;
1383 }
1384 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001385
adamdunkelsb2486562003-04-11 20:22:03 +00001386 /* Check if the mouse pointer has moved. */
1387 if(ctk_mouse_x() != mouse_x ||
1388 ctk_mouse_y() != mouse_y) {
1389 mouse_x = ctk_mouse_x();
1390 mouse_y = ctk_mouse_y();
1391 mouse_moved = 1;
1392 }
1393
1394 mxc = ctk_mouse_xtoc(mouse_x);
1395 myc = ctk_mouse_ytoc(mouse_y);
1396#endif /* CTK_CONF_MOUSE_SUPPORT */
1397
1398
adamdunkels66109622003-04-24 17:17:10 +00001399#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001400 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001401 if(ctk_arch_keyavail()
1402#if CTK_CONF_MOUSE_SUPPORT
1403 || mouse_moved || mouse_button_changed
1404#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001405 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001406 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1407 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001408 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001409 }
adamdunkels66109622003-04-24 17:17:10 +00001410 } else
1411#endif /* CTK_CONF_SCREENSAVER */
1412 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001413#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001414 /* If there is any change in the mouse conditions, find out in
1415 which window the mouse pointer currently is in order to send
1416 the correct signals, or bring a window to focus. */
1417 if(mouse_moved || mouse_button_changed) {
1418 ctk_mouse_show();
1419 screensaver_timer = 0;
1420
1421 if(myc == 0) {
1422 /* Here we should do whatever needs to be done when the mouse
1423 moves around and clicks in the menubar. */
1424 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001425 static unsigned char titlelen;
1426
adamdunkelsb2486562003-04-11 20:22:03 +00001427 /* Find out which menu that the mouse pointer is in. Start
1428 with the ->next menu after the desktop menu. We assume
1429 that the menus start one character from the left screen
1430 side and that the desktop menu is farthest to the
1431 right. */
1432 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001433 for(menu = menus.menus->next;
1434 menu != NULL; menu = menu->next) {
1435 titlelen = menu->titlelen;
1436 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001437 break;
adamdunkelse0683312003-04-09 09:02:52 +00001438 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001439 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001440 }
adamdunkelsb2486562003-04-11 20:22:03 +00001441
1442 /* Also check desktop menu. */
1443 if(mxc >= width - 7 &&
1444 mxc <= width - 1) {
1445 menu = &desktopmenu;
1446 }
1447
1448 menus.open = menu;
1449 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001450 }
adamdunkelse0683312003-04-09 09:02:52 +00001451 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001452 --myc;
1453
1454 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001455 static unsigned char nitems;
1456
adamdunkelsb2486562003-04-11 20:22:03 +00001457 /* Do whatever needs to be done when a menu is open. */
1458
adamdunkelscf90b0d2003-08-09 13:34:16 +00001459 /* First check if the mouse pointer is in the currently open
1460 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001461 if(menus.open == &desktopmenu) {
1462 menux = width - CTK_CONF_MENUWIDTH;
1463 } else {
1464 menux = 1;
1465 for(menu = menus.menus->next; menu != menus.open;
1466 menu = menu->next) {
1467 menux += menu->titlelen;
1468 }
1469 }
1470
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001471 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001472 /* Find out which of the menu items the mouse is pointing
1473 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001474 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1475 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001476 menus.open->active = myc;
1477 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001478 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001479 }
adamdunkelsb2486562003-04-11 20:22:03 +00001480 }
1481
1482 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001483 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001484 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001485 redraw |= activate_menu();
1486 } else {
1487 lastmenu = menus.open;
1488 menus.open = NULL;
1489 redraw |= REDRAW_MENUPART;
1490 }
1491 } else {
1492 redraw |= REDRAW_MENUS;
1493 }
1494 } else {
1495
adamdunkels965e2922003-06-30 20:44:57 +00001496 /* Walk through the windows from top to bottom to see in
1497 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001498 if(dialog != NULL) {
1499 window = dialog;
1500 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001501 for(window = windows; window != NULL;
1502 window = window->next) {
1503
adamdunkelsb2486562003-04-11 20:22:03 +00001504 /* Check if the mouse is within the window. */
1505 if(mxc >= window->x &&
1506 mxc <= window->x + window->w &&
1507 myc >= window->y &&
1508 myc <= window->y + window->h) {
1509 break;
1510 }
1511 }
1512 }
1513
1514
1515 /* If we didn't find any window, and there are no windows
1516 open, the mouse pointer will definately be within the
1517 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001518 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001519 window = &desktop_window;
1520 }
1521
adamdunkels965e2922003-06-30 20:44:57 +00001522 /* If the mouse pointer moves around outside of the
1523 currently focused window (or dialog), we should not have
1524 any focused widgets in the focused window so we make sure
1525 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001526 if(windows != NULL &&
1527 window != windows &&
1528 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001529 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001530 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001531 redraw |= REDRAW_WIDGETS;*/
1532 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001533 }
1534
1535 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001536 /* If the mouse was clicked outside of the current window,
1537 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001538 if(dialog == NULL &&
1539 window != &desktop_window &&
1540 window != windows &&
1541 mouse_clicked) {
1542 /* Bring window to front. */
1543 ctk_window_open(window);
1544 redraw |= REDRAW_ALL;
1545 } else {
1546
adamdunkels965e2922003-06-30 20:44:57 +00001547 /* Find out which widget currently is under the mouse
1548 pointer and give it focus, unless it already has
1549 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001550 mxc = mxc - window->x - 1;
1551 myc = myc - window->y - 1;
1552
adamdunkels965e2922003-06-30 20:44:57 +00001553 /* See if the mouse pointer is on a widget. If so, it
1554 should be selected and, if the button is clicked,
1555 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001556 for(widget = window->active; widget != NULL;
1557 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001558
adamdunkelsb2486562003-04-11 20:22:03 +00001559 if(mxc >= widget->x &&
1560 mxc <= widget->x + widget->w &&
1561 (myc == widget->y ||
1562 ((widget->type == CTK_WIDGET_BITMAP ||
1563 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1564 widget->type == CTK_WIDGET_ICON) &&
1565 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001566 myc <= widget->y +
1567 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001568 break;
1569 }
1570 }
1571
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001572
1573 /* if the mouse is moved in the focused window, we emit
1574 a ctk_signal_pointer_move signal to the owner of the
1575 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001576 if(mouse_moved &&
1577 (window != &desktop_window ||
1578 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001579
adamdunkelsb2486562003-04-11 20:22:03 +00001580 dispatcher_emit(ctk_signal_pointer_move, NULL,
1581 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001582
1583 /* If there was a focused widget that is not below the
1584 mouse pointer, we remove focus from the widget and
1585 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001586 if(window->focused != NULL &&
1587 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001588 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001589 if(CTK_WIDGET_TYPE(window->focused) ==
1590 CTK_WIDGET_TEXTENTRY) {
1591 ((struct ctk_textentry *)(window->focused))->state =
1592 CTK_TEXTENTRY_NORMAL;
1593 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001594 window->focused = NULL;*/
1595 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001596 }
1597 redraw |= REDRAW_WIDGETS;
1598 if(widget != NULL) {
1599 select_widget(widget);
1600 }
1601 }
1602
1603 if(mouse_button_changed) {
1604 dispatcher_emit(ctk_signal_pointer_button,
1605 (ek_data_t)mouse_button,
1606 window->owner);
1607 if(mouse_clicked && widget != NULL) {
1608 select_widget(widget);
1609 redraw |= activate(widget);
1610 }
1611 }
1612 }
1613 }
1614 }
adamdunkelsc4902862003-04-09 00:30:45 +00001615 }
1616 }
adamdunkels19a787c2003-04-09 09:22:24 +00001617#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001618
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001619 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001620
1621 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001622
1623 screensaver_timer = 0;
1624
adamdunkelsb2486562003-04-11 20:22:03 +00001625 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001626
1627 if(dialog != NULL) {
1628 window = dialog;
1629 } else if(windows != NULL) {
1630 window = windows;
1631 } else {
1632 window = &desktop_window;
1633 }
1634 widget = window->focused;
1635
1636
1637 if(widget != NULL &&
1638 widget->type == CTK_WIDGET_TEXTENTRY &&
1639 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1640 textentry_input(c, (struct ctk_textentry *)widget);
1641 add_redrawwidget(widget);
1642#if CTK_CONF_MENUS
1643 } else if(menus.open != NULL) {
1644 redraw |= menus_input(c);
1645#endif /* CTK_CONF_MENUS */
1646 } else {
1647 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001648 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001649 switch_focus_widget(DOWN);
1650 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001651 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001652 switch_focus_widget(UP);
1653 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001654#if CTK_CONF_MENUS
1655 case CTK_CONF_MENU_KEY:
1656 if(dialog == NULL) {
1657 if(lastmenu == NULL) {
1658 menus.open = menus.menus;
1659 } else {
1660 menus.open = lastmenu;
1661 }
1662 menus.open->active = 0;
1663 redraw |= REDRAW_MENUS;
1664 }
1665 break;
1666#endif /* CTK_CONF_MENUS */
1667 case CTK_CONF_WINDOWSWITCH_KEY:
1668 if(windows != NULL) {
1669 for(window = windows; window->next != NULL;
1670 window = window->next);
1671 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001672 }
1673 break;
1674 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001675 if(c == CH_ENTER &&
1676 widget != NULL) {
1677 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001678 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001679 if(widget != NULL &&
1680 widget->type == CTK_WIDGET_TEXTENTRY) {
1681 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1682 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001683 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001684 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001685 /* window->focused = NULL;*/
1686 unfocus_widget(window->focused);
adamdunkels6afc9c52004-03-25 09:53:35 +00001687 dispatcher_post_synch(ctk_signal_keypress, (void *)c,
1688 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001689 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001690 }
1691 break;
1692 }
1693 }
1694
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001695#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001696 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001697 widgetptr = redraw_widgets;
1698 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001699 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001700 *widgetptr = NULL;
1701 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001702 }
1703 redraw &= ~REDRAW_WIDGETS;
1704 redraw_widgetptr = 0;
1705 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001706#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001707 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001708#if CTK_CONF_WINDOWMOVE
1709 } else if(mode == CTK_MODE_WINDOWMOVE) {
1710
1711 redraw = 0;
1712
1713 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001714
1715#if CTK_CONF_MOUSE_SUPPORT
1716
1717 /* If the mouse has moved, we move the window as well. */
1718 if(mouse_moved) {
1719
1720 if(window->w + mxc + 2 >= width) {
1721 window->x = width - 2 - window->w;
1722 } else {
1723 window->x = mxc;
1724 }
1725
1726 if(window->h + myc + 2 >= height) {
1727 window->y = height - 2 - window->h;
1728 } else {
1729 window->y = myc;
1730 }
1731 if(window->y > 0) {
1732 --window->y;
1733 }
1734
1735 redraw = REDRAW_ALL;
1736 }
1737
1738 /* Check if the mouse has been clicked, and stop moving the window
1739 if so. */
1740 if(mouse_button_changed &&
1741 mouse_button == 0) {
1742 mode = CTK_MODE_NORMAL;
1743 redraw = REDRAW_ALL;
1744 }
1745#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001746
1747 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1748
1749 screensaver_timer = 0;
1750
1751 c = ctk_arch_getkey();
1752
1753 switch(c) {
1754 case CH_CURS_RIGHT:
1755 ++window->x;
1756 if(window->x + window->w + 1 >= width) {
1757 --window->x;
1758 }
1759 redraw = REDRAW_ALL;
1760 break;
1761 case CH_CURS_LEFT:
1762 if(window->x > 0) {
1763 --window->x;
1764 }
1765 redraw = REDRAW_ALL;
1766 break;
1767 case CH_CURS_DOWN:
1768 ++window->y;
1769 if(window->y + window->h + 2 >= height) {
1770 --window->y;
1771 }
1772 redraw = REDRAW_ALL;
1773 break;
1774 case CH_CURS_UP:
1775 if(window->y > 0) {
1776 --window->y;
1777 }
1778 redraw = REDRAW_ALL;
1779 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001780 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001781 mode = CTK_MODE_NORMAL;
1782 redraw = REDRAW_ALL;
1783 break;
1784 }
1785 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001786#endif /* CTK_CONF_WINDOWMOVE */
1787 }
adamdunkelsb2486562003-04-11 20:22:03 +00001788
1789 if(redraw & REDRAW_ALL) {
1790 do_redraw_all(1, height);
1791#if CTK_CONF_MENUS
1792 } else if(redraw & REDRAW_MENUPART) {
1793 do_redraw_all(1, maxnitems + 1);
1794 } else if(redraw & REDRAW_MENUS) {
1795 ctk_draw_menus(&menus);
1796#endif /* CTK_CONF_MENUS */
1797 } else if(redraw & REDRAW_FOCUS) {
1798 if(dialog != NULL) {
1799 ctk_window_redraw(dialog);
1800 } else if(windows != NULL) {
1801 ctk_window_redraw(windows);
1802 } else {
1803 ctk_window_redraw(&desktop_window);
1804 }
1805 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001806 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001807 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001808 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001809 *widgetptr = NULL;
1810 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001811 }
1812 }
1813 redraw = 0;
1814 redraw_widgetptr = 0;
1815
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001816}
1817/*-----------------------------------------------------------------------------------*/
adamdunkelse937ded2003-10-01 07:53:57 +00001818/** @} */
1819/** @} */
1820