blob: 1d5076ffe3c17ae9be882289baaffc93d1ba0fa3 [file] [log] [blame]
adamdunkels35298692003-08-31 22:16:49 +00001/**
2 * \file
adamdunkels1e45c6d2003-09-02 21:47:27 +00003 * The Contiki Toolkit CTK, the Contiki GUI.
adamdunkels35298692003-08-31 22:16:49 +00004 * \author Adam Dunkels <adam@dunkels.com>
5 *
6 * The Contiki Toolkit (CTK) provides the graphical user interface for
7 * the Contiki system.
8 *
adamdunkels1e45c6d2003-09-02 21:47:27 +00009 *
10 *
adamdunkels35298692003-08-31 22:16:49 +000011 *
12 */
13
adamdunkelsca9ddcb2003-03-19 14:13:31 +000014/*
adamdunkels35298692003-08-31 22:16:49 +000015 * Copyright (c) 2002-2003, Adam Dunkels.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000016 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above
24 * copyright notice, this list of conditions and the following
25 * disclaimer in the documentation and/or other materials provided
26 * with the distribution.
adamdunkels35298692003-08-31 22:16:49 +000027 * 3. The name of the author may not be used to endorse or promote
adamdunkelsca9ddcb2003-03-19 14:13:31 +000028 * products derived from this software without specific prior
29 * written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
32 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 * This file is part of the "ctk" console GUI toolkit for cc65
44 *
adamdunkels1e45c6d2003-09-02 21:47:27 +000045 * $Id: ctk.c,v 1.32 2003/09/02 21:47:27 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000046 *
47 */
48
adamdunkelsd07a5422003-04-05 12:22:35 +000049#include "cc.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000050#include "ek.h"
51#include "dispatcher.h"
52#include "ctk.h"
53#include "ctk-draw.h"
54#include "ctk-conf.h"
adamdunkelsc4902862003-04-09 00:30:45 +000055#include "ctk-mouse.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000056
adamdunkels591724c2003-08-01 00:07:19 +000057#include <string.h>
58
adamdunkelsca9ddcb2003-03-19 14:13:31 +000059static unsigned char height, width;
60
61static unsigned char mode;
62
63static struct ctk_window desktop_window;
64static struct ctk_window *windows;
65static struct ctk_window *dialog;
66
67#if CTK_CONF_MENUS
68static struct ctk_menus menus;
69static struct ctk_menu *lastmenu;
70static struct ctk_menu desktopmenu;
71#endif /* CTK_CONF_MENUS */
72
73#ifndef NULL
74#define NULL (void *)0
75#endif /* NULL */
76
adamdunkelsca9ddcb2003-03-19 14:13:31 +000077#define REDRAW_NONE 0
78#define REDRAW_ALL 1
79#define REDRAW_FOCUS 2
80#define REDRAW_WIDGETS 4
81#define REDRAW_MENUS 8
82#define REDRAW_MENUPART 16
83
84#define MAX_REDRAWWIDGETS 4
85static unsigned char redraw;
86static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
87static unsigned char redraw_widgetptr;
88static unsigned char maxnitems;
89
90static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000091#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000092#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000093#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000095#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096
adamdunkelsc4902862003-04-09 00:30:45 +000097static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +000099 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000100static ek_id_t ctkid;
101
adamdunkels35298692003-08-31 22:16:49 +0000102ek_signal_t
103
104 /** Emitted for every key being pressed. The key is passed as signal
105 data.*/
106 ctk_signal_keypress,
107
108 /** Emitted when a widget is activated (pressed). A pointer to the
109 widget is passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000110 ctk_signal_widget_activate,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000111
112 /** \deprecated Same as ctk_signal_widget_activate. */
adamdunkels35298692003-08-31 22:16:49 +0000113 ctk_signal_button_activate,
114
115 /** Emitted when a widget is selected. A pointer to the widget is
116 passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000117 ctk_signal_widget_select,
adamdunkels1e45c6d2003-09-02 21:47:27 +0000118
119 /** \deprecated Same as ctk_signal_widget_select. */
adamdunkels35298692003-08-31 22:16:49 +0000120 ctk_signal_button_hover,
121
122 /** Emitted when a hyperlink is activated. The signal is broadcast
123 to all listeners. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000124 ctk_signal_hyperlink_activate,
adamdunkels35298692003-08-31 22:16:49 +0000125
adamdunkels1e45c6d2003-09-02 21:47:27 +0000126 /** \deprecated Same as ctk_signal_widget_select.. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000127 ctk_signal_hyperlink_hover,
adamdunkels35298692003-08-31 22:16:49 +0000128
129 /** Emitted when a menu item is activated. The number of the menu
130 item is passed as signal data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000131 ctk_signal_menu_activate,
adamdunkels35298692003-08-31 22:16:49 +0000132
133 /** Emitted when a window is closed. A pointer to the window is
134 passed as signal data. */
adamdunkelsc4902862003-04-09 00:30:45 +0000135 ctk_signal_window_close,
adamdunkels35298692003-08-31 22:16:49 +0000136
137 /** Emitted when the mouse pointer is moved. A NULL pointer is
138 passed as signal data and it is up to the listening process to
139 check the position of the mouse using the CTK mouse API.*/
adamdunkelsc4902862003-04-09 00:30:45 +0000140 ctk_signal_pointer_move,
adamdunkels35298692003-08-31 22:16:49 +0000141
142 /** Emitted when a mouse button is pressed. The button is passed as
143 signal data to the listening process. */
adamdunkelsb2486562003-04-11 20:22:03 +0000144 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000145
adamdunkels66109622003-04-24 17:17:10 +0000146#if CTK_CONF_SCREENSAVER
adamdunkels9795b2e2003-08-09 23:32:37 +0000147ek_signal_t ctk_signal_screensaver_stop,
148 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000149#endif /* CTK_CONF_SCREENSAVER */
150
151
adamdunkels19a787c2003-04-09 09:22:24 +0000152#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000153unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000154#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000155
adamdunkels9795b2e2003-08-09 23:32:37 +0000156static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000157unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels9795b2e2003-08-09 23:32:37 +0000158static ek_clock_t start, current;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000159
160#if CTK_CONF_MENUS
161/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000162/**
163 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000164 *
165 * Creates the leftmost menu, "Desktop". Since the desktop menu
166 * contains the list of all open windows, this function will be called
167 * whenever a window is opened or closed.
168 */
adamdunkels35298692003-08-31 22:16:49 +0000169/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000170static void
171make_desktopmenu(void)
172{
173 struct ctk_window *w;
174
175 desktopmenu.nitems = 0;
176
177 if(windows == NULL) {
178 ctk_menuitem_add(&desktopmenu, "(No windows)");
179 } else {
180 for(w = windows; w != NULL; w = w->next) {
181 ctk_menuitem_add(&desktopmenu, w->title);
182 }
183 }
184}
185#endif /* CTK_CONF_MENUS */
186/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000187/**
188 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000189 *
adamdunkels35298692003-08-31 22:16:49 +0000190 * This function must be called before any other CTK function, but
191 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000192 */
adamdunkels35298692003-08-31 22:16:49 +0000193/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000194void
195ctk_init(void)
196{
197 ctkid = dispatcher_start(&p);
198
199 windows = NULL;
200 dialog = NULL;
201
202#if CTK_CONF_MENUS
203 ctk_menu_new(&desktopmenu, "Desktop");
204 make_desktopmenu();
205 menus.menus = menus.desktopmenu = &desktopmenu;
206#endif /* CTK_CONF_MENUS */
207
adamdunkelsb2486562003-04-11 20:22:03 +0000208#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000209 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000210 ctk_mouse_show();
211#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000212
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000213 ctk_draw_init();
214
215 height = ctk_draw_height();
216 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000217
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000218 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000219
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000220 ctk_signal_keypress = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000221
222 ctk_signal_button_activate =
223 ctk_signal_widget_activate = dispatcher_sigalloc();
224
225 ctk_signal_button_hover =
226 ctk_signal_hyperlink_hover =
227 ctk_signal_widget_select = dispatcher_sigalloc();
228
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000229 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000230
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000231 ctk_signal_menu_activate = dispatcher_sigalloc();
232 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000233
234 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000235 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000236
237
238#if CTK_CONF_SCREENSAVER
239 ctk_signal_screensaver_start = dispatcher_sigalloc();
240 ctk_signal_screensaver_stop = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000241#endif /* CTK_CONF_SCREENSAVER */
242
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000243
244 mode = CTK_MODE_NORMAL;
245
246 iconx = ICONX_START;
247 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000248
249 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000250
251 start = ek_clock();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000252}
253/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000254/**
255 * Sets the current CTK mode.
256 *
257 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
258 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
259 * keypresses and mouse pointer movements are processed and the screen
260 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
261 * performed and the first key press or pointer movement will cause
262 * the ctk_signal_screensaver_stop to be emitted. In the
263 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
264 * ignored and no screen redraws are made.
265 *
266 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000267 */
adamdunkels35298692003-08-31 22:16:49 +0000268/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000269void
270ctk_mode_set(unsigned char m) {
271 mode = m;
272}
273/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000274/**
275 * Retrieves the current CTK mode.
276 *
277 * \return The current CTK mode.
278 */
279/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000280unsigned char
281ctk_mode_get(void) {
282 return mode;
283}
284/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000285/**
286 * Add an icon to the desktop.
287 *
288 * \param icon The icon to be added.
289 */
290/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000291void
adamdunkels35298692003-08-31 22:16:49 +0000292ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000293{
294#if CTK_CONF_ICONS
295 icon->x = iconx;
296 icon->y = icony;
adamdunkels35298692003-08-31 22:16:49 +0000297 icon->widget.icon.owner = DISPATCHER_CURRENT();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000298
299 icony += ICONY_DELTA;
300 if(icony >= ICONY_MAX) {
301 icony = ICONY_START;
302 iconx += ICONX_DELTA;
303 }
304
305 ctk_widget_add(&desktop_window, icon);
306#endif /* CTK_CONF_ICONS */
307}
308/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000309/**
310 * Open a dialog box.
311 *
312 * \param d The dialog to be opened.
313 */
314/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000315void
316ctk_dialog_open(struct ctk_window *d)
317{
318 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000319 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000320}
321/*-----------------------------------------------------------------------------------*/
322/**
323 * Close the dialog box, if one is open.
324 *
325 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000326/*-----------------------------------------------------------------------------------*/
327void
328ctk_dialog_close(void)
329{
330 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000331 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000332}
333/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000334/**
335 * Open a window, or bring window to front if already open.
336 *
337 * \param w The window to be opened.
338 */
339/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000340void
adamdunkelsd07a5422003-04-05 12:22:35 +0000341ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000342{
343 struct ctk_window *w2;
344
345 /* Check if already open. */
346 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
347 if(w2 == NULL) {
348 /* Not open, so we add it at the head of the list of open
349 windows. */
350 w->next = windows;
351 if(windows != NULL) {
352 windows->prev = w;
353 }
354 windows = w;
355 w->prev = NULL;
356 } else {
357 /* Window already open, so we move it to the front of the windows
358 list. */
359 if(w != windows) {
360 if(w->next != NULL) {
361 w->next->prev = w->prev;
362 }
363 if(w->prev != NULL) {
364 w->prev->next = w->next;
365 }
366 w->next = windows;
367 windows->prev = w;
368 windows = w;
369 w->prev = NULL;
370 }
371 }
372
373#if CTK_CONF_MENUS
374 /* Recreate the Desktop menu's window entries.*/
375 make_desktopmenu();
376#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000377
378 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000379}
380/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000381/**
382 * Close a window if it is open.
383 *
384 * If the window is not open, this function does nothing.
385 *
386 * \param w The window to be closed.
387 */
388/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000389void
390ctk_window_close(struct ctk_window *w)
391{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000392 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000393
394 if(w == NULL) {
395 return;
396 }
397
398 /* Check if the window to be closed is the first window on the
399 list. */
400 if(w == windows) {
401 windows = w->next;
402 if(windows != NULL) {
403 windows->prev = NULL;
404 }
405 w->next = w->prev = NULL;
406 } else {
407 /* Otherwise we step through the list until we find the window
408 before the one to be closed. We then redirect its ->next
409 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000410 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
411
412 if(w2 == NULL) {
413 /* The window wasn't open, so there is nothing more for us to
414 do. */
415 return;
416 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000417
418 if(w->next != NULL) {
419 w->next->prev = w->prev;
420 }
421 w2->next = w->next;
422
423 w->next = w->prev = NULL;
424 }
425
426#if CTK_CONF_MENUS
427 /* Recreate the Desktop menu's window entries.*/
428 make_desktopmenu();
429#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000430 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000431}
432/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000433/**
434 * \internal Create the move and close buttons on the window titlebar.
435 */
436/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000437static void
438make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000439{
440#if CTK_CONF_WINDOWMOVE
441 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
442#else
443 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
444#endif /* CTK_CONF_WINDOWMOVE */
445 CTK_WIDGET_ADD(window, &window->titlebutton);
446
447
448#if CTK_CONF_WINDOWCLOSE
449 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
450#else
451 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
452#endif /* CTK_CONF_WINDOWCLOSE */
453 CTK_WIDGET_ADD(window, &window->closebutton);
454}
455/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000456/**
457 * Remove all widgets from a window.
458 *
459 * \param w The window to be cleared.
460 */
461/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000462void
adamdunkels35298692003-08-31 22:16:49 +0000463ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000464{
adamdunkels35298692003-08-31 22:16:49 +0000465 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000466
adamdunkels35298692003-08-31 22:16:49 +0000467 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000468}
469/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000470/**
471 * Add a menu to the menu bar.
472 *
473 * \param menu The menu to be added.
474 *
475 * \note Do not call this function multiple times for the same menu,
476 * as no check is made to see if the menu already is in the menu bar.
477 */
478/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000479void
480ctk_menu_add(struct ctk_menu *menu)
481{
482#if CTK_CONF_MENUS
483 struct ctk_menu *m;
484
485 if(lastmenu == NULL) {
486 lastmenu = menu;
487 }
488
489 for(m = menus.menus; m->next != NULL; m = m->next) {
490 if(m == menu) {
491 return;
492 }
493 }
494 m->next = menu;
495 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000496
497 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000498#endif /* CTK_CONF_MENUS */
499}
500/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000501/**
502 * Remove a menu from the menu bar.
503 *
504 * \param menu The menu to be removed.
505 */
506/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000507void
508ctk_menu_remove(struct ctk_menu *menu)
509{
510#if CTK_CONF_MENUS
511 struct ctk_menu *m;
512
513 for(m = menus.menus; m->next != NULL; m = m->next) {
514 if(m->next == menu) {
515 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000516 if(menu == lastmenu) {
517 lastmenu = NULL;
518 }
519 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000520 return;
521 }
522 }
523#endif /* CTK_CONF_MENUS */
524}
525/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000526/**
527 * \internal Redraws everything on the screen within the clip
528 * interval.
529 *
530 * \param clipy1 The upper bound of the clip interval
531 * \param clipy2 The lower bound of the clip interval
532 */
533/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000534static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000535do_redraw_all(unsigned char clipy1, unsigned char clipy2)
536{
537 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000538 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000539
540 if(mode != CTK_MODE_NORMAL &&
541 mode != CTK_MODE_WINDOWMOVE) {
542 return;
543 }
544
545 ctk_draw_clear(clipy1, clipy2);
546
547 /* Draw widgets in root window */
548 for(widget = desktop_window.active;
549 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000550 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000551 }
552
553 /* Draw windows */
554 if(windows != NULL) {
555 /* Find the last window.*/
556 for(w = windows; w->next != NULL; w = w->next);
557
558 /* Draw the windows from back to front. */
559 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000560 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000561 ctk_draw_window(w, 0, clipy1, clipy2);
562 }
563 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000564 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000565 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
566 }
567
568 /* Draw dialog (if any) */
569 if(dialog != NULL) {
570 ctk_draw_dialog(dialog);
571 }
572
573#if CTK_CONF_MENUS
574 ctk_draw_menus(&menus);
575#endif /* CTK_CONF_MENUS */
576}
577/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000578/**
579 * Redraw the entire desktop.
580 *
581 * \param d The desktop to be redrawn.
582 *
583 * \note Currently the parameter d is not used, but must be set to
584 * NULL.
585 */
586/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000587void
adamdunkels965e2922003-06-30 20:44:57 +0000588ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000589{
590 if(DISPATCHER_CURRENT() == ctkid) {
591 if(mode == CTK_MODE_NORMAL ||
592 mode == CTK_MODE_WINDOWMOVE) {
593 do_redraw_all(1, height);
594 }
595 } else {
596 redraw |= REDRAW_ALL;
597 }
598}
599/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000600/**
601 * Redraw a window.
602 *
603 * This function redraws the window, but only if it is the foremost
604 * one on the desktop.
605 *
606 * \param w The window to be redrawn.
607 */
608/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000609void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000610ctk_window_redraw(struct ctk_window *w)
611{
612 /* Only redraw the window if it is a dialog or if it is the foremost
613 window. */
614 if(mode != CTK_MODE_NORMAL) {
615 return;
616 }
617
618 if(w == dialog) {
619 ctk_draw_dialog(w);
620 } else if(dialog == NULL &&
621#if CTK_CONF_MENUS
622 menus.open == NULL &&
623#endif /* CTK_CONF_MENUS */
624 windows == w) {
625 ctk_draw_window(w, CTK_FOCUS_WINDOW,
626 0, height);
627 }
628}
629/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000630/**
631 * \internal Creates a new window.
632 *
633 * \param window The window to be created.
634 * \param w The width of the window.
635 * \param h The height of the window.
636 * \param title The title of the window.
637 */
638/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000639static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000640window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000641 unsigned char w, unsigned char h,
642 char *title)
643{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000644
645 if(w >= width - 2) {
646 window->x = 0;
647 } else {
648 window->x = (width - w - 2) / 2;
649 }
650 if(h >= height - 3) {
651 window->y = 0;
652 } else {
653 window->y = (height - h - 1) / 2;
654 }
655
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000656 window->w = w;
657 window->h = h;
658 window->title = title;
659 if(title != NULL) {
660 window->titlelen = strlen(title);
661 } else {
662 window->titlelen = 0;
663 }
664 window->next = window->prev = NULL;
665 window->owner = DISPATCHER_CURRENT();
666 window->active = window->inactive = window->focused = NULL;
667}
668/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000669/**
670 * Create a new window.
671 *
672 * Creates a new window. The memory for the window structure must
673 * already be allocated by the caller, and is usually done with a
674 * static declaration.
675 *
676 * This function sets up the internal structure of the ctk_window
677 * struct and creates the move and close buttons, but it does not open
678 * the window. The window must be explicitly opened by calling the
679 * ctk_window_open() function.
680 *
681 * \param window The window to be created.
682 * \param w The width of the new window.
683 * \param h The height of the new window.
684 * \param title The title of the new window.
685 */
686/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000687void
688ctk_window_new(struct ctk_window *window,
689 unsigned char w, unsigned char h,
690 char *title)
691{
692 window_new(window, w, h, title);
693
694 make_windowbuttons(window);
695}
696/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000697/**
698 * Creates a new dialog.
699 *
700 * This function only sets up the internal structure of the ctk_window
701 * struct but does not open the dialog. The dialog must be explicitly
702 * opened by calling the ctk_dialog_open() function.
703 *
704 * \param dialog The dialog to be created.
705 * \param w The width of the dialog.
706 * \param h The height of the dialog.
707 */
708/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000709void
adamdunkels35298692003-08-31 22:16:49 +0000710ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000711 unsigned char w, unsigned char h)
712{
adamdunkels35298692003-08-31 22:16:49 +0000713 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000714}
adamdunkels3af580f2003-08-11 22:27:13 +0000715/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000716/**
717 * Creates a new menu.
718 *
719 * This function sets up the internal structure of the menu, but does
720 * not add it to the menubar. Use the function ctk_menu_add() for that
721 * purpose.
722 *
723 * \param menu The menu to be created.
724 * \param title The title of the menu.
725 */
726/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000727void
adamdunkelsd07a5422003-04-05 12:22:35 +0000728ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000729 char *title)
730{
731#if CTK_CONF_MENUS
732 menu->next = NULL;
733 menu->title = title;
734 menu->titlelen = strlen(title);
735 menu->active = 0;
736 menu->nitems = 0;
737#endif /* CTK_CONF_MENUS */
738}
739/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000740/**
741 * Adds a menu item to a menu.
742 *
743 * In CTK, each menu item is identified by a number which is unique
744 * within each menu. When a menu item is selected, a
745 * ctk_menuitem_activated signal is emitted and the menu item number
746 * is passed as signal data with the signal.
747 *
748 * \param menu The menu to which the menu item should be added.
749 * \param name The name of the menu item.
750 * \return The number of the menu item.
751 */
752/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000753unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000754ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000755 char *name)
756{
757#if CTK_CONF_MENUS
758 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
759 return 0;
760 }
761 menu->items[menu->nitems].title = name;
762 menu->items[menu->nitems].titlelen = strlen(name);
763 return menu->nitems++;
764#else
765 return 0;
766#endif /* CTK_CONF_MENUS */
767}
768/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000769/**
770 * \internal Adds a widget to the list of widgets that should be
771 * redrawn.
772 *
773 * \param w The widget that should be redrawn.
774 */
775/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000776static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000777add_redrawwidget(struct ctk_widget *w)
778{
779 static unsigned char i;
780
781 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
782 redraw |= REDRAW_FOCUS;
783 } else {
784 redraw |= REDRAW_WIDGETS;
785 /* Check if it is in the queue already. If so, we don't add it
786 again. */
787 for(i = 0; i < redraw_widgetptr; ++i) {
788 if(redraw_widgets[i] == w) {
789 return;
790 }
791 }
792 redraw_widgets[redraw_widgetptr++] = w;
793 }
794}
795/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000796/**
797 * \internal Checks if a widget redrawn and adds it to the list of
798 * widgets to be redrawn.
799 *
800 * A widget can be redrawn only if the current CTK mode is
801 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
802 * foremost window.
803 *
804 * \param widget The widget that should be redrawn.
805 */
806/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000807static void
808widget_redraw(struct ctk_widget *widget)
809{
810 struct ctk_window *window;
811
812 if(mode != CTK_MODE_NORMAL || widget == NULL) {
813 return;
814 }
815
816 /* Only redraw widgets that are in the foremost window. If we would
817 allow redrawing widgets in non-focused windows, we would have to
818 redraw all the windows that cover the non-focused window as well,
819 which would lead to flickering.
820
821 Also, we avoid drawing any widgets when the menus are active.
822 */
823
824#if CTK_CONF_MENUS
825 if(menus.open == NULL)
826#endif /* CTK_CONF_MENUS */
827 {
828 window = widget->window;
829 if(window == dialog) {
830 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
831 } else if(dialog == NULL &&
832 (window == windows ||
833 window == &desktop_window)) {
834 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
835 }
836 }
837}
838/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000839/**
840 * Redraws a widget.
841 *
842 * This function will set a flag which causes the widget to be redrawn
843 * next time the CTK process is scheduled.
844 *
845 * \param widget The widget that is to be redrawn.
846 *
847 * \note This function should usually not be called directly since it
848 * requires typecasting of the widget parameter. The wrapper macro
849 * CTK_WIDGET_REDRAW() does the required typecast and should be used
850 * instead.
851 */
852/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000853void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854ctk_widget_redraw(struct ctk_widget *widget)
855{
856 struct ctk_window *window;
857
adamdunkels9f667f22003-04-16 18:29:19 +0000858 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000859 return;
860 }
861
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000862 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000863 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000864 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000865}
866/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000867/**
868 * Adds a widget to a window.
869 *
870 * This function adds a widget to a window. The order of which the
871 * widgets are added is important, as it sets the order to which
872 * widgets are cycled with the widget selection keys.
873 *
874 * \param window The window to which the widhet should be added.
875 * \param widget The widget to be added.
876 */
877/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000878void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000879ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
880 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000881{
882 if(widget->type == CTK_WIDGET_LABEL ||
883 widget->type == CTK_WIDGET_SEPARATOR) {
884 widget->next = window->inactive;
885 window->inactive = widget;
886 widget->window = window;
887 } else {
888 widget->next = window->active;
889 window->active = widget;
890 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000891 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000892 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000893 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000894 }
895}
896/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000897/**
898 * Gets the width of the desktop.
899 *
900 * \param d The desktop.
901 * \return The width of the desktop, in characters.
902 *
903 * \note The d parameter is currently unused and must be set to NULL.
904 */
905/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000906unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000907ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000908{
909 return ctk_draw_width();
910}
911/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000912/**
913 * Gets the height of the desktop.
914 *
915 * \param d The desktop.
916 * \return The height of the desktop, in characters.
917 *
918 * \note The d parameter is currently unused and must be set to NULL.
919 */
920/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000921unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000922ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000923{
924 return ctk_draw_height();
925}
926/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000927/**
928 * \internal Selects a widget in the window of the widget.
929 *
930 * \param focus The widget to be focused.
931 */
932/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000933static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000934select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000935{
936 struct ctk_window *window;
937
938 window = focus->window;
939
940 if(focus != window->focused) {
941 window->focused = focus;
942 /* The operation changed the focus, so we emit a "hover" signal
943 for those widgets that support it. */
944
945 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
946 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
947 window->owner);
948 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
949 dispatcher_emit(ctk_signal_button_hover, window->focused,
950 window->owner);
951 }
952
953 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000954
955 dispatcher_emit(ctk_signal_widget_select, focus,
956 focus->window->owner);
957
adamdunkelse0683312003-04-09 09:02:52 +0000958 }
959
960}
961/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000962#define UP 0
963#define DOWN 1
964#define LEFT 2
965#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000966static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000967switch_focus_widget(unsigned char direction)
968{
969 register struct ctk_window *window;
970 register struct ctk_widget *focus;
971 struct ctk_widget *widget;
972
973
974 if(dialog != NULL) {
975 window = dialog;
976 } else {
977 window = windows;
978 }
979
980 /* If there are no windows open, we move focus around between the
981 icons on the root window instead. */
982 if(window == NULL) {
983 window = &desktop_window;
984 }
985
986 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000987 if(focus == NULL) {
988 focus = window->active;
989 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000990 add_redrawwidget(focus);
991
992 if((direction & 1) == 0) {
993 /* Move focus "up" */
994 focus = focus->next;
995 } else {
996 /* Move focus "down" */
997 for(widget = window->active;
998 widget != NULL; widget = widget->next) {
999 if(widget->next == focus) {
1000 break;
1001 }
1002 }
1003 focus = widget;
1004 if(focus == NULL) {
1005 if(window->active != NULL) {
1006 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001007 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001008 }
1009 }
1010 }
1011 if(focus == NULL) {
1012 focus = window->active;
1013 }
adamdunkelse0683312003-04-09 09:02:52 +00001014
adamdunkelsb2486562003-04-11 20:22:03 +00001015 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001016}
1017/*-----------------------------------------------------------------------------------*/
1018#if CTK_CONF_MENUS
1019static void
1020switch_open_menu(unsigned char rightleft)
1021{
1022 struct ctk_menu *menu;
1023
1024 if(rightleft == 0) {
1025 /* Move right */
1026 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1027 if(menu->next == menus.open) {
1028 break;
1029 }
1030 }
1031 lastmenu = menus.open;
1032 menus.open = menu;
1033 if(menus.open == NULL) {
1034 for(menu = menus.menus;
1035 menu->next != NULL; menu = menu->next);
1036 menus.open = menu;
1037 }
1038 } else {
1039 /* Move to left */
1040 lastmenu = menus.open;
1041 menus.open = menus.open->next;
1042 if(menus.open == NULL) {
1043 menus.open = menus.menus;
1044 }
1045 }
1046
adamdunkels66109622003-04-24 17:17:10 +00001047 menus.open->active = 0;
1048
1049 /* if(menus.open->nitems > maxnitems) {
1050 maxnitems = menus.open->nitems;
1051 }*/
1052
adamdunkels965e2922003-06-30 20:44:57 +00001053 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001054}
1055/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001056static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001057switch_menu_item(unsigned char updown)
1058{
1059 register struct ctk_menu *m;
1060
1061 m = menus.open;
1062
1063 if(updown == 0) {
1064 /* Move up */
1065 if(m->active == 0) {
1066 m->active = m->nitems - 1;
1067 } else {
1068 --m->active;
1069 if(m->items[m->active].title[0] == '-') {
1070 --m->active;
1071 }
1072 }
1073 } else {
1074 /* Move down */
1075 if(m->active >= m->nitems - 1) {
1076 m->active = 0;
1077 } else {
1078 ++m->active;
1079 if(m->items[m->active].title[0] == '-') {
1080 ++m->active;
1081 }
1082 }
1083 }
1084
1085}
1086#endif /* CTK_CONF_MENUS */
1087/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001088static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001089activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001090{
1091 static unsigned char len;
1092
1093 if(w->type == CTK_WIDGET_BUTTON) {
1094 if(w == (struct ctk_widget *)&windows->closebutton) {
1095#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +00001096 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001097 ctk_window_close(windows);
1098 return REDRAW_ALL;
1099#endif /* CTK_CONF_WINDOWCLOSE */
1100 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1101#if CTK_CONF_WINDOWCLOSE
1102 mode = CTK_MODE_WINDOWMOVE;
1103#endif /* CTK_CONF_WINDOWCLOSE */
1104 } else {
adamdunkels58917a82003-04-18 00:18:38 +00001105 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001106 w->window->owner);
1107 }
1108#if CTK_CONF_ICONS
1109 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +00001110 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001111 w->widget.icon.owner);
1112#endif /* CTK_CONF_ICONS */
1113 } else if(w->type == CTK_WIDGET_HYPERLINK) {
1114 dispatcher_emit(ctk_signal_hyperlink_activate, w,
1115 DISPATCHER_BROADCAST);
1116 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1117 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1118 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1119 len = strlen(w->widget.textentry.text);
1120 if(w->widget.textentry.xpos > len) {
1121 w->widget.textentry.xpos = len;
1122 }
1123 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1124 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +00001125 dispatcher_emit(ctk_signal_widget_activate, w,
1126 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001127 }
1128 add_redrawwidget(w);
1129 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001130 } else {
1131 dispatcher_emit(ctk_signal_widget_activate, w,
1132 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001133 }
1134 return REDRAW_NONE;
1135}
1136/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001137static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001138textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001139 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001140{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001141 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001142 static unsigned char len, txpos, typos, tlen;
1143
1144 txpos = t->xpos;
1145 typos = t->ypos;
1146 tlen = t->len;
1147
1148 cptr = &t->text[txpos + typos * tlen];
1149
1150 switch(c) {
1151 case CH_CURS_LEFT:
1152 if(txpos > 0) {
1153 --txpos;
1154 }
1155 break;
1156
1157 case CH_CURS_RIGHT:
1158 if(txpos < tlen &&
1159 *cptr != 0) {
1160 ++txpos;
1161 }
1162 break;
1163
1164 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001165 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001166 break;
1167
1168 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001169 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001170 break;
1171
1172 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001173 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1174 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001175 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001176 break;
1177
adamdunkels9795b2e2003-08-09 23:32:37 +00001178 case CTK_CONF_WIDGETDOWN_KEY:
1179 t->state = CTK_TEXTENTRY_NORMAL;
1180 switch_focus_widget(DOWN);
1181 break;
1182 case CTK_CONF_WIDGETUP_KEY:
1183 t->state = CTK_TEXTENTRY_NORMAL;
1184 switch_focus_widget(UP);
1185 break;
1186
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001187 default:
1188 len = tlen - txpos - 1;
1189 if(c == CH_DEL) {
1190 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +00001191 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001192 *(cptr + len - 1) = 0;
1193 --txpos;
1194 }
1195 } else {
1196 if(len > 0) {
1197 cptr2 = cptr + len - 1;
1198 while(cptr2 + 1 > cptr) {
1199 *(cptr2 + 1) = *cptr2;
1200 --cptr2;
1201 }
1202
1203 *cptr = c;
1204 ++txpos;
1205 }
1206 }
1207 break;
1208 }
1209
1210 t->xpos = txpos;
1211 t->ypos = typos;
1212}
1213/*-----------------------------------------------------------------------------------*/
1214#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001215static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001216activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001217{
1218 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001219
adamdunkelsb2486562003-04-11 20:22:03 +00001220 lastmenu = menus.open;
1221 if(menus.open == &desktopmenu) {
1222 for(w = windows; w != NULL; w = w->next) {
1223 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1224 ctk_window_open(w);
1225 menus.open = NULL;
1226 return REDRAW_ALL;
1227 }
1228 }
1229 } else {
1230 dispatcher_emit(ctk_signal_menu_activate, menus.open,
1231 DISPATCHER_BROADCAST);
1232 }
1233 menus.open = NULL;
1234 return REDRAW_MENUPART;
1235}
1236/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001237static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001238menus_input(ctk_arch_key_t c)
1239{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001240
1241 if(menus.open->nitems > maxnitems) {
1242 maxnitems = menus.open->nitems;
1243 }
1244
1245
1246 switch(c) {
1247 case CH_CURS_RIGHT:
1248 switch_open_menu(1);
1249
1250 return REDRAW_MENUPART;
1251
1252 case CH_CURS_DOWN:
1253 switch_menu_item(1);
1254 return REDRAW_MENUS;
1255
1256 case CH_CURS_LEFT:
1257 switch_open_menu(0);
1258 return REDRAW_MENUPART;
1259
1260 case CH_CURS_UP:
1261 switch_menu_item(0);
1262 return REDRAW_MENUS;
1263
1264 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001265 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266
adamdunkels88ed9c42003-03-28 12:10:09 +00001267 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001268 lastmenu = menus.open;
1269 menus.open = NULL;
1270 return REDRAW_MENUPART;
1271 }
adamdunkelsb2486562003-04-11 20:22:03 +00001272
1273 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001274}
1275#endif /* CTK_CONF_MENUS */
1276/*-----------------------------------------------------------------------------------*/
1277static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001278timer(void)
1279{
1280 if(mode == CTK_MODE_NORMAL) {
1281 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001282 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001283#if CTK_CONF_SCREENSAVER
1284 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1285 DISPATCHER_BROADCAST);
1286#ifdef CTK_SCREENSAVER_INIT
1287 CTK_SCREENSAVER_INIT();
1288#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001289
adamdunkelscf90b0d2003-08-09 13:34:16 +00001290#endif /* CTK_CONF_SCREENSAVER */
1291 screensaver_timer = 0;
1292 }
1293 }
1294}
1295/*-----------------------------------------------------------------------------------*/
1296static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001297unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1298{
1299 if(w != NULL) {
1300 redraw |= REDRAW_WIDGETS;
1301 add_redrawwidget(w);
1302 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1303 ((struct ctk_textentry *)w)->state =
1304 CTK_TEXTENTRY_NORMAL;
1305 }
1306 w->window->focused = NULL;
1307 }
1308}
1309/*-----------------------------------------------------------------------------------*/
1310static void
adamdunkelsc4902862003-04-09 00:30:45 +00001311ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001312{
1313 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001314 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001315 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001316 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001317 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001318#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001319 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1320 mouse_clicked;
1321 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001322 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001323
adamdunkels19a787c2003-04-09 09:22:24 +00001324#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001325
1326
1327 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001328
adamdunkels9795b2e2003-08-09 23:32:37 +00001329 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001330 timer();
1331 start = current;
1332 }
1333
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001334#if CTK_CONF_MENUS
1335 if(menus.open != NULL) {
1336 maxnitems = menus.open->nitems;
1337 } else {
1338 maxnitems = 0;
1339 }
1340#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001341
1342#if CTK_CONF_MOUSE_SUPPORT
1343 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1344
1345 /* See if there is any change in the buttons. */
1346 if(ctk_mouse_button() != mouse_button) {
1347 mouse_button = ctk_mouse_button();
1348 mouse_button_changed = 1;
1349 if(mouse_button == 0) {
1350 mouse_clicked = 1;
1351 }
1352 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001353
adamdunkelsb2486562003-04-11 20:22:03 +00001354 /* Check if the mouse pointer has moved. */
1355 if(ctk_mouse_x() != mouse_x ||
1356 ctk_mouse_y() != mouse_y) {
1357 mouse_x = ctk_mouse_x();
1358 mouse_y = ctk_mouse_y();
1359 mouse_moved = 1;
1360 }
1361
1362 mxc = ctk_mouse_xtoc(mouse_x);
1363 myc = ctk_mouse_ytoc(mouse_y);
1364#endif /* CTK_CONF_MOUSE_SUPPORT */
1365
1366
adamdunkels66109622003-04-24 17:17:10 +00001367#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001368 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001369 if(ctk_arch_keyavail()
1370#if CTK_CONF_MOUSE_SUPPORT
1371 || mouse_moved || mouse_button_changed
1372#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001373 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001374 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1375 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001376 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001377 }
adamdunkels66109622003-04-24 17:17:10 +00001378 } else
1379#endif /* CTK_CONF_SCREENSAVER */
1380 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001381#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001382 /* If there is any change in the mouse conditions, find out in
1383 which window the mouse pointer currently is in order to send
1384 the correct signals, or bring a window to focus. */
1385 if(mouse_moved || mouse_button_changed) {
1386 ctk_mouse_show();
1387 screensaver_timer = 0;
1388
1389 if(myc == 0) {
1390 /* Here we should do whatever needs to be done when the mouse
1391 moves around and clicks in the menubar. */
1392 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001393 static unsigned char titlelen;
1394
adamdunkelsb2486562003-04-11 20:22:03 +00001395 /* Find out which menu that the mouse pointer is in. Start
1396 with the ->next menu after the desktop menu. We assume
1397 that the menus start one character from the left screen
1398 side and that the desktop menu is farthest to the
1399 right. */
1400 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001401 for(menu = menus.menus->next;
1402 menu != NULL; menu = menu->next) {
1403 titlelen = menu->titlelen;
1404 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001405 break;
adamdunkelse0683312003-04-09 09:02:52 +00001406 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001407 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001408 }
adamdunkelsb2486562003-04-11 20:22:03 +00001409
1410 /* Also check desktop menu. */
1411 if(mxc >= width - 7 &&
1412 mxc <= width - 1) {
1413 menu = &desktopmenu;
1414 }
1415
1416 menus.open = menu;
1417 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001418 }
adamdunkelse0683312003-04-09 09:02:52 +00001419 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001420 --myc;
1421
1422 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001423 static unsigned char nitems;
1424
adamdunkelsb2486562003-04-11 20:22:03 +00001425 /* Do whatever needs to be done when a menu is open. */
1426
adamdunkelscf90b0d2003-08-09 13:34:16 +00001427 /* First check if the mouse pointer is in the currently open
1428 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001429 if(menus.open == &desktopmenu) {
1430 menux = width - CTK_CONF_MENUWIDTH;
1431 } else {
1432 menux = 1;
1433 for(menu = menus.menus->next; menu != menus.open;
1434 menu = menu->next) {
1435 menux += menu->titlelen;
1436 }
1437 }
1438
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001439 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001440 /* Find out which of the menu items the mouse is pointing
1441 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001442 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1443 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001444 menus.open->active = myc;
1445 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001446 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001447 }
adamdunkelsb2486562003-04-11 20:22:03 +00001448 }
1449
1450 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001451 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001452 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001453 redraw |= activate_menu();
1454 } else {
1455 lastmenu = menus.open;
1456 menus.open = NULL;
1457 redraw |= REDRAW_MENUPART;
1458 }
1459 } else {
1460 redraw |= REDRAW_MENUS;
1461 }
1462 } else {
1463
adamdunkels965e2922003-06-30 20:44:57 +00001464 /* Walk through the windows from top to bottom to see in
1465 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001466 if(dialog != NULL) {
1467 window = dialog;
1468 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001469 for(window = windows; window != NULL;
1470 window = window->next) {
1471
adamdunkelsb2486562003-04-11 20:22:03 +00001472 /* Check if the mouse is within the window. */
1473 if(mxc >= window->x &&
1474 mxc <= window->x + window->w &&
1475 myc >= window->y &&
1476 myc <= window->y + window->h) {
1477 break;
1478 }
1479 }
1480 }
1481
1482
1483 /* If we didn't find any window, and there are no windows
1484 open, the mouse pointer will definately be within the
1485 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001486 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001487 window = &desktop_window;
1488 }
1489
adamdunkels965e2922003-06-30 20:44:57 +00001490 /* If the mouse pointer moves around outside of the
1491 currently focused window (or dialog), we should not have
1492 any focused widgets in the focused window so we make sure
1493 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001494 if(windows != NULL &&
1495 window != windows &&
1496 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001497 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001498 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001499 redraw |= REDRAW_WIDGETS;*/
1500 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001501 }
1502
1503 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001504 /* If the mouse was clicked outside of the current window,
1505 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001506 if(dialog == NULL &&
1507 window != &desktop_window &&
1508 window != windows &&
1509 mouse_clicked) {
1510 /* Bring window to front. */
1511 ctk_window_open(window);
1512 redraw |= REDRAW_ALL;
1513 } else {
1514
adamdunkels965e2922003-06-30 20:44:57 +00001515 /* Find out which widget currently is under the mouse
1516 pointer and give it focus, unless it already has
1517 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001518 mxc = mxc - window->x - 1;
1519 myc = myc - window->y - 1;
1520
adamdunkels965e2922003-06-30 20:44:57 +00001521 /* See if the mouse pointer is on a widget. If so, it
1522 should be selected and, if the button is clicked,
1523 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001524 for(widget = window->active; widget != NULL;
1525 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001526
adamdunkelsb2486562003-04-11 20:22:03 +00001527 if(mxc >= widget->x &&
1528 mxc <= widget->x + widget->w &&
1529 (myc == widget->y ||
1530 ((widget->type == CTK_WIDGET_BITMAP ||
1531 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1532 widget->type == CTK_WIDGET_ICON) &&
1533 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001534 myc <= widget->y +
1535 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001536 break;
1537 }
1538 }
1539
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001540
1541 /* if the mouse is moved in the focused window, we emit
1542 a ctk_signal_pointer_move signal to the owner of the
1543 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001544 if(mouse_moved &&
1545 (window != &desktop_window ||
1546 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001547
adamdunkelsb2486562003-04-11 20:22:03 +00001548 dispatcher_emit(ctk_signal_pointer_move, NULL,
1549 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001550
1551 /* If there was a focused widget that is not below the
1552 mouse pointer, we remove focus from the widget and
1553 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001554 if(window->focused != NULL &&
1555 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001556 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001557 if(CTK_WIDGET_TYPE(window->focused) ==
1558 CTK_WIDGET_TEXTENTRY) {
1559 ((struct ctk_textentry *)(window->focused))->state =
1560 CTK_TEXTENTRY_NORMAL;
1561 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001562 window->focused = NULL;*/
1563 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001564 }
1565 redraw |= REDRAW_WIDGETS;
1566 if(widget != NULL) {
1567 select_widget(widget);
1568 }
1569 }
1570
1571 if(mouse_button_changed) {
1572 dispatcher_emit(ctk_signal_pointer_button,
1573 (ek_data_t)mouse_button,
1574 window->owner);
1575 if(mouse_clicked && widget != NULL) {
1576 select_widget(widget);
1577 redraw |= activate(widget);
1578 }
1579 }
1580 }
1581 }
1582 }
adamdunkelsc4902862003-04-09 00:30:45 +00001583 }
1584 }
adamdunkels19a787c2003-04-09 09:22:24 +00001585#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001586
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001587 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001588
1589 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001590
1591 screensaver_timer = 0;
1592
adamdunkelsb2486562003-04-11 20:22:03 +00001593 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001594
1595 if(dialog != NULL) {
1596 window = dialog;
1597 } else if(windows != NULL) {
1598 window = windows;
1599 } else {
1600 window = &desktop_window;
1601 }
1602 widget = window->focused;
1603
1604
1605 if(widget != NULL &&
1606 widget->type == CTK_WIDGET_TEXTENTRY &&
1607 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1608 textentry_input(c, (struct ctk_textentry *)widget);
1609 add_redrawwidget(widget);
1610#if CTK_CONF_MENUS
1611 } else if(menus.open != NULL) {
1612 redraw |= menus_input(c);
1613#endif /* CTK_CONF_MENUS */
1614 } else {
1615 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001616 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001617 switch_focus_widget(DOWN);
1618 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001619 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001620 switch_focus_widget(UP);
1621 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001622#if CTK_CONF_MENUS
1623 case CTK_CONF_MENU_KEY:
1624 if(dialog == NULL) {
1625 if(lastmenu == NULL) {
1626 menus.open = menus.menus;
1627 } else {
1628 menus.open = lastmenu;
1629 }
1630 menus.open->active = 0;
1631 redraw |= REDRAW_MENUS;
1632 }
1633 break;
1634#endif /* CTK_CONF_MENUS */
1635 case CTK_CONF_WINDOWSWITCH_KEY:
1636 if(windows != NULL) {
1637 for(window = windows; window->next != NULL;
1638 window = window->next);
1639 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001640 }
1641 break;
1642 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001643 if(c == CH_ENTER &&
1644 widget != NULL) {
1645 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001646 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001647 if(widget != NULL &&
1648 widget->type == CTK_WIDGET_TEXTENTRY) {
1649 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1650 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001651 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001652 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001653 /* window->focused = NULL;*/
1654 unfocus_widget(window->focused);
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001655 dispatcher_fastemit(ctk_signal_keypress, (void *)c,
1656 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001657 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001658 }
1659 break;
1660 }
1661 }
1662
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001663#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001664 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001665 widgetptr = redraw_widgets;
1666 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001667 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001668 *widgetptr = NULL;
1669 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001670 }
1671 redraw &= ~REDRAW_WIDGETS;
1672 redraw_widgetptr = 0;
1673 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001674#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001675 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001676#if CTK_CONF_WINDOWMOVE
1677 } else if(mode == CTK_MODE_WINDOWMOVE) {
1678
1679 redraw = 0;
1680
1681 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001682
1683#if CTK_CONF_MOUSE_SUPPORT
1684
1685 /* If the mouse has moved, we move the window as well. */
1686 if(mouse_moved) {
1687
1688 if(window->w + mxc + 2 >= width) {
1689 window->x = width - 2 - window->w;
1690 } else {
1691 window->x = mxc;
1692 }
1693
1694 if(window->h + myc + 2 >= height) {
1695 window->y = height - 2 - window->h;
1696 } else {
1697 window->y = myc;
1698 }
1699 if(window->y > 0) {
1700 --window->y;
1701 }
1702
1703 redraw = REDRAW_ALL;
1704 }
1705
1706 /* Check if the mouse has been clicked, and stop moving the window
1707 if so. */
1708 if(mouse_button_changed &&
1709 mouse_button == 0) {
1710 mode = CTK_MODE_NORMAL;
1711 redraw = REDRAW_ALL;
1712 }
1713#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001714
1715 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1716
1717 screensaver_timer = 0;
1718
1719 c = ctk_arch_getkey();
1720
1721 switch(c) {
1722 case CH_CURS_RIGHT:
1723 ++window->x;
1724 if(window->x + window->w + 1 >= width) {
1725 --window->x;
1726 }
1727 redraw = REDRAW_ALL;
1728 break;
1729 case CH_CURS_LEFT:
1730 if(window->x > 0) {
1731 --window->x;
1732 }
1733 redraw = REDRAW_ALL;
1734 break;
1735 case CH_CURS_DOWN:
1736 ++window->y;
1737 if(window->y + window->h + 2 >= height) {
1738 --window->y;
1739 }
1740 redraw = REDRAW_ALL;
1741 break;
1742 case CH_CURS_UP:
1743 if(window->y > 0) {
1744 --window->y;
1745 }
1746 redraw = REDRAW_ALL;
1747 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001748 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001749 mode = CTK_MODE_NORMAL;
1750 redraw = REDRAW_ALL;
1751 break;
1752 }
1753 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001754#endif /* CTK_CONF_WINDOWMOVE */
1755 }
adamdunkelsb2486562003-04-11 20:22:03 +00001756
1757 if(redraw & REDRAW_ALL) {
1758 do_redraw_all(1, height);
1759#if CTK_CONF_MENUS
1760 } else if(redraw & REDRAW_MENUPART) {
1761 do_redraw_all(1, maxnitems + 1);
1762 } else if(redraw & REDRAW_MENUS) {
1763 ctk_draw_menus(&menus);
1764#endif /* CTK_CONF_MENUS */
1765 } else if(redraw & REDRAW_FOCUS) {
1766 if(dialog != NULL) {
1767 ctk_window_redraw(dialog);
1768 } else if(windows != NULL) {
1769 ctk_window_redraw(windows);
1770 } else {
1771 ctk_window_redraw(&desktop_window);
1772 }
1773 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001774 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001775 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001776 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001777 *widgetptr = NULL;
1778 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001779 }
1780 }
1781 redraw = 0;
1782 redraw_widgetptr = 0;
1783
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001784}
1785/*-----------------------------------------------------------------------------------*/