blob: 97b327f93c9c435a0ac4071f9d6d258ea36ba759 [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 *
adamdunkels0404ef12003-09-04 19:36:04 +000045 * $Id: ctk.c,v 1.33 2003/09/04 19:36:04 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.
adamdunkels0404ef12003-09-04 19:36:04 +0000289 *
290 * \param id The process ID of the process that owns the icon.
adamdunkels35298692003-08-31 22:16:49 +0000291 */
292/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000293void
adamdunkels0404ef12003-09-04 19:36:04 +0000294ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon, ek_id_t id)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000295{
adamdunkels0404ef12003-09-04 19:36:04 +0000296#if CTK_CONF_ICONS
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000297 icon->x = iconx;
298 icon->y = icony;
adamdunkels0404ef12003-09-04 19:36:04 +0000299 icon->widget.icon.owner = id;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000300
301 icony += ICONY_DELTA;
302 if(icony >= ICONY_MAX) {
303 icony = ICONY_START;
304 iconx += ICONX_DELTA;
305 }
306
307 ctk_widget_add(&desktop_window, icon);
308#endif /* CTK_CONF_ICONS */
309}
310/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000311/**
312 * Open a dialog box.
313 *
314 * \param d The dialog to be opened.
315 */
316/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000317void
318ctk_dialog_open(struct ctk_window *d)
319{
320 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000321 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000322}
323/*-----------------------------------------------------------------------------------*/
324/**
325 * Close the dialog box, if one is open.
326 *
327 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000328/*-----------------------------------------------------------------------------------*/
329void
330ctk_dialog_close(void)
331{
332 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000333 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000334}
335/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000336/**
337 * Open a window, or bring window to front if already open.
338 *
339 * \param w The window to be opened.
340 */
341/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000342void
adamdunkelsd07a5422003-04-05 12:22:35 +0000343ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000344{
345 struct ctk_window *w2;
346
347 /* Check if already open. */
348 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
349 if(w2 == NULL) {
350 /* Not open, so we add it at the head of the list of open
351 windows. */
352 w->next = windows;
353 if(windows != NULL) {
354 windows->prev = w;
355 }
356 windows = w;
357 w->prev = NULL;
358 } else {
359 /* Window already open, so we move it to the front of the windows
360 list. */
361 if(w != windows) {
362 if(w->next != NULL) {
363 w->next->prev = w->prev;
364 }
365 if(w->prev != NULL) {
366 w->prev->next = w->next;
367 }
368 w->next = windows;
369 windows->prev = w;
370 windows = w;
371 w->prev = NULL;
372 }
373 }
374
375#if CTK_CONF_MENUS
376 /* Recreate the Desktop menu's window entries.*/
377 make_desktopmenu();
378#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000379
380 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000381}
382/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000383/**
384 * Close a window if it is open.
385 *
386 * If the window is not open, this function does nothing.
387 *
388 * \param w The window to be closed.
389 */
390/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000391void
392ctk_window_close(struct ctk_window *w)
393{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000394 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000395
396 if(w == NULL) {
397 return;
398 }
399
400 /* Check if the window to be closed is the first window on the
401 list. */
402 if(w == windows) {
403 windows = w->next;
404 if(windows != NULL) {
405 windows->prev = NULL;
406 }
407 w->next = w->prev = NULL;
408 } else {
409 /* Otherwise we step through the list until we find the window
410 before the one to be closed. We then redirect its ->next
411 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000412 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
413
414 if(w2 == NULL) {
415 /* The window wasn't open, so there is nothing more for us to
416 do. */
417 return;
418 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000419
420 if(w->next != NULL) {
421 w->next->prev = w->prev;
422 }
423 w2->next = w->next;
424
425 w->next = w->prev = NULL;
426 }
427
428#if CTK_CONF_MENUS
429 /* Recreate the Desktop menu's window entries.*/
430 make_desktopmenu();
431#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000432 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000433}
434/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000435/**
436 * \internal Create the move and close buttons on the window titlebar.
437 */
438/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000439static void
440make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000441{
442#if CTK_CONF_WINDOWMOVE
443 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
444#else
445 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
446#endif /* CTK_CONF_WINDOWMOVE */
447 CTK_WIDGET_ADD(window, &window->titlebutton);
448
449
450#if CTK_CONF_WINDOWCLOSE
451 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
452#else
453 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
454#endif /* CTK_CONF_WINDOWCLOSE */
455 CTK_WIDGET_ADD(window, &window->closebutton);
456}
457/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000458/**
459 * Remove all widgets from a window.
460 *
461 * \param w The window to be cleared.
462 */
463/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000464void
adamdunkels35298692003-08-31 22:16:49 +0000465ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000466{
adamdunkels35298692003-08-31 22:16:49 +0000467 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000468
adamdunkels35298692003-08-31 22:16:49 +0000469 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000470}
471/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000472/**
473 * Add a menu to the menu bar.
474 *
475 * \param menu The menu to be added.
476 *
477 * \note Do not call this function multiple times for the same menu,
478 * as no check is made to see if the menu already is in the menu bar.
479 */
480/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000481void
482ctk_menu_add(struct ctk_menu *menu)
483{
484#if CTK_CONF_MENUS
485 struct ctk_menu *m;
486
487 if(lastmenu == NULL) {
488 lastmenu = menu;
489 }
490
491 for(m = menus.menus; m->next != NULL; m = m->next) {
492 if(m == menu) {
493 return;
494 }
495 }
496 m->next = menu;
497 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000498
499 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000500#endif /* CTK_CONF_MENUS */
501}
502/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000503/**
504 * Remove a menu from the menu bar.
505 *
506 * \param menu The menu to be removed.
507 */
508/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000509void
510ctk_menu_remove(struct ctk_menu *menu)
511{
512#if CTK_CONF_MENUS
513 struct ctk_menu *m;
514
515 for(m = menus.menus; m->next != NULL; m = m->next) {
516 if(m->next == menu) {
517 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000518 if(menu == lastmenu) {
519 lastmenu = NULL;
520 }
521 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000522 return;
523 }
524 }
525#endif /* CTK_CONF_MENUS */
526}
527/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000528/**
529 * \internal Redraws everything on the screen within the clip
530 * interval.
531 *
532 * \param clipy1 The upper bound of the clip interval
533 * \param clipy2 The lower bound of the clip interval
534 */
535/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000536static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000537do_redraw_all(unsigned char clipy1, unsigned char clipy2)
538{
539 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000540 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000541
542 if(mode != CTK_MODE_NORMAL &&
543 mode != CTK_MODE_WINDOWMOVE) {
544 return;
545 }
546
547 ctk_draw_clear(clipy1, clipy2);
548
549 /* Draw widgets in root window */
550 for(widget = desktop_window.active;
551 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000552 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000553 }
554
555 /* Draw windows */
556 if(windows != NULL) {
557 /* Find the last window.*/
558 for(w = windows; w->next != NULL; w = w->next);
559
560 /* Draw the windows from back to front. */
561 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000562 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000563 ctk_draw_window(w, 0, clipy1, clipy2);
564 }
565 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000566 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000567 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
568 }
569
570 /* Draw dialog (if any) */
571 if(dialog != NULL) {
572 ctk_draw_dialog(dialog);
573 }
574
575#if CTK_CONF_MENUS
576 ctk_draw_menus(&menus);
577#endif /* CTK_CONF_MENUS */
578}
579/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000580/**
581 * Redraw the entire desktop.
582 *
583 * \param d The desktop to be redrawn.
584 *
585 * \note Currently the parameter d is not used, but must be set to
586 * NULL.
587 */
588/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000589void
adamdunkels965e2922003-06-30 20:44:57 +0000590ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000591{
592 if(DISPATCHER_CURRENT() == ctkid) {
593 if(mode == CTK_MODE_NORMAL ||
594 mode == CTK_MODE_WINDOWMOVE) {
595 do_redraw_all(1, height);
596 }
597 } else {
598 redraw |= REDRAW_ALL;
599 }
600}
601/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000602/**
603 * Redraw a window.
604 *
605 * This function redraws the window, but only if it is the foremost
606 * one on the desktop.
607 *
608 * \param w The window to be redrawn.
609 */
610/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000611void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000612ctk_window_redraw(struct ctk_window *w)
613{
614 /* Only redraw the window if it is a dialog or if it is the foremost
615 window. */
616 if(mode != CTK_MODE_NORMAL) {
617 return;
618 }
619
620 if(w == dialog) {
621 ctk_draw_dialog(w);
622 } else if(dialog == NULL &&
623#if CTK_CONF_MENUS
624 menus.open == NULL &&
625#endif /* CTK_CONF_MENUS */
626 windows == w) {
627 ctk_draw_window(w, CTK_FOCUS_WINDOW,
628 0, height);
629 }
630}
631/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000632/**
633 * \internal Creates a new window.
634 *
635 * \param window The window to be created.
636 * \param w The width of the window.
637 * \param h The height of the window.
638 * \param title The title of the window.
639 */
640/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000641static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000642window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000643 unsigned char w, unsigned char h,
644 char *title)
645{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000646
647 if(w >= width - 2) {
648 window->x = 0;
649 } else {
650 window->x = (width - w - 2) / 2;
651 }
652 if(h >= height - 3) {
653 window->y = 0;
654 } else {
655 window->y = (height - h - 1) / 2;
656 }
657
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000658 window->w = w;
659 window->h = h;
660 window->title = title;
661 if(title != NULL) {
662 window->titlelen = strlen(title);
663 } else {
664 window->titlelen = 0;
665 }
666 window->next = window->prev = NULL;
667 window->owner = DISPATCHER_CURRENT();
668 window->active = window->inactive = window->focused = NULL;
669}
670/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000671/**
672 * Create a new window.
673 *
674 * Creates a new window. The memory for the window structure must
675 * already be allocated by the caller, and is usually done with a
676 * static declaration.
677 *
678 * This function sets up the internal structure of the ctk_window
679 * struct and creates the move and close buttons, but it does not open
680 * the window. The window must be explicitly opened by calling the
681 * ctk_window_open() function.
682 *
683 * \param window The window to be created.
684 * \param w The width of the new window.
685 * \param h The height of the new window.
686 * \param title The title of the new window.
687 */
688/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000689void
690ctk_window_new(struct ctk_window *window,
691 unsigned char w, unsigned char h,
692 char *title)
693{
694 window_new(window, w, h, title);
695
696 make_windowbuttons(window);
697}
698/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000699/**
700 * Creates a new dialog.
701 *
702 * This function only sets up the internal structure of the ctk_window
703 * struct but does not open the dialog. The dialog must be explicitly
704 * opened by calling the ctk_dialog_open() function.
705 *
706 * \param dialog The dialog to be created.
707 * \param w The width of the dialog.
708 * \param h The height of the dialog.
709 */
710/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000711void
adamdunkels35298692003-08-31 22:16:49 +0000712ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000713 unsigned char w, unsigned char h)
714{
adamdunkels35298692003-08-31 22:16:49 +0000715 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000716}
adamdunkels3af580f2003-08-11 22:27:13 +0000717/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000718/**
719 * Creates a new menu.
720 *
721 * This function sets up the internal structure of the menu, but does
722 * not add it to the menubar. Use the function ctk_menu_add() for that
723 * purpose.
724 *
725 * \param menu The menu to be created.
726 * \param title The title of the menu.
727 */
728/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000729void
adamdunkelsd07a5422003-04-05 12:22:35 +0000730ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000731 char *title)
732{
733#if CTK_CONF_MENUS
734 menu->next = NULL;
735 menu->title = title;
736 menu->titlelen = strlen(title);
737 menu->active = 0;
738 menu->nitems = 0;
739#endif /* CTK_CONF_MENUS */
740}
741/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000742/**
743 * Adds a menu item to a menu.
744 *
745 * In CTK, each menu item is identified by a number which is unique
746 * within each menu. When a menu item is selected, a
747 * ctk_menuitem_activated signal is emitted and the menu item number
748 * is passed as signal data with the signal.
749 *
750 * \param menu The menu to which the menu item should be added.
751 * \param name The name of the menu item.
752 * \return The number of the menu item.
753 */
754/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000755unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000756ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000757 char *name)
758{
759#if CTK_CONF_MENUS
760 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
761 return 0;
762 }
763 menu->items[menu->nitems].title = name;
764 menu->items[menu->nitems].titlelen = strlen(name);
765 return menu->nitems++;
766#else
767 return 0;
768#endif /* CTK_CONF_MENUS */
769}
770/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000771/**
772 * \internal Adds a widget to the list of widgets that should be
773 * redrawn.
774 *
775 * \param w The widget that should be redrawn.
776 */
777/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000778static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000779add_redrawwidget(struct ctk_widget *w)
780{
781 static unsigned char i;
782
783 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
784 redraw |= REDRAW_FOCUS;
785 } else {
786 redraw |= REDRAW_WIDGETS;
787 /* Check if it is in the queue already. If so, we don't add it
788 again. */
789 for(i = 0; i < redraw_widgetptr; ++i) {
790 if(redraw_widgets[i] == w) {
791 return;
792 }
793 }
794 redraw_widgets[redraw_widgetptr++] = w;
795 }
796}
797/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000798/**
799 * \internal Checks if a widget redrawn and adds it to the list of
800 * widgets to be redrawn.
801 *
802 * A widget can be redrawn only if the current CTK mode is
803 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
804 * foremost window.
805 *
806 * \param widget The widget that should be redrawn.
807 */
808/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000809static void
810widget_redraw(struct ctk_widget *widget)
811{
812 struct ctk_window *window;
813
814 if(mode != CTK_MODE_NORMAL || widget == NULL) {
815 return;
816 }
817
818 /* Only redraw widgets that are in the foremost window. If we would
819 allow redrawing widgets in non-focused windows, we would have to
820 redraw all the windows that cover the non-focused window as well,
821 which would lead to flickering.
822
823 Also, we avoid drawing any widgets when the menus are active.
824 */
825
826#if CTK_CONF_MENUS
827 if(menus.open == NULL)
828#endif /* CTK_CONF_MENUS */
829 {
830 window = widget->window;
831 if(window == dialog) {
832 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
833 } else if(dialog == NULL &&
834 (window == windows ||
835 window == &desktop_window)) {
836 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
837 }
838 }
839}
840/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000841/**
842 * Redraws a widget.
843 *
844 * This function will set a flag which causes the widget to be redrawn
845 * next time the CTK process is scheduled.
846 *
847 * \param widget The widget that is to be redrawn.
848 *
849 * \note This function should usually not be called directly since it
850 * requires typecasting of the widget parameter. The wrapper macro
851 * CTK_WIDGET_REDRAW() does the required typecast and should be used
852 * instead.
853 */
854/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000855void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856ctk_widget_redraw(struct ctk_widget *widget)
857{
858 struct ctk_window *window;
859
adamdunkels9f667f22003-04-16 18:29:19 +0000860 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000861 return;
862 }
863
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000864 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000865 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000866 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000867}
868/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000869/**
870 * Adds a widget to a window.
871 *
872 * This function adds a widget to a window. The order of which the
873 * widgets are added is important, as it sets the order to which
874 * widgets are cycled with the widget selection keys.
875 *
876 * \param window The window to which the widhet should be added.
877 * \param widget The widget to be added.
878 */
879/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000880void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000881ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
882 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883{
884 if(widget->type == CTK_WIDGET_LABEL ||
885 widget->type == CTK_WIDGET_SEPARATOR) {
886 widget->next = window->inactive;
887 window->inactive = widget;
888 widget->window = window;
889 } else {
890 widget->next = window->active;
891 window->active = widget;
892 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000893 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000894 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000895 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000896 }
897}
898/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000899/**
900 * Gets the width of the desktop.
901 *
902 * \param d The desktop.
903 * \return The width of the desktop, in characters.
904 *
905 * \note The d parameter is currently unused and must be set to NULL.
906 */
907/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000908unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000909ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000910{
911 return ctk_draw_width();
912}
913/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000914/**
915 * Gets the height of the desktop.
916 *
917 * \param d The desktop.
918 * \return The height of the desktop, in characters.
919 *
920 * \note The d parameter is currently unused and must be set to NULL.
921 */
922/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000923unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000924ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000925{
926 return ctk_draw_height();
927}
928/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000929/**
930 * \internal Selects a widget in the window of the widget.
931 *
932 * \param focus The widget to be focused.
933 */
934/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000935static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000936select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000937{
938 struct ctk_window *window;
939
940 window = focus->window;
941
942 if(focus != window->focused) {
943 window->focused = focus;
944 /* The operation changed the focus, so we emit a "hover" signal
945 for those widgets that support it. */
946
947 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
948 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
949 window->owner);
950 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
951 dispatcher_emit(ctk_signal_button_hover, window->focused,
952 window->owner);
953 }
954
955 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000956
957 dispatcher_emit(ctk_signal_widget_select, focus,
958 focus->window->owner);
959
adamdunkelse0683312003-04-09 09:02:52 +0000960 }
961
962}
963/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000964#define UP 0
965#define DOWN 1
966#define LEFT 2
967#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000968static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000969switch_focus_widget(unsigned char direction)
970{
971 register struct ctk_window *window;
972 register struct ctk_widget *focus;
973 struct ctk_widget *widget;
974
975
976 if(dialog != NULL) {
977 window = dialog;
978 } else {
979 window = windows;
980 }
981
982 /* If there are no windows open, we move focus around between the
983 icons on the root window instead. */
984 if(window == NULL) {
985 window = &desktop_window;
986 }
987
988 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000989 if(focus == NULL) {
990 focus = window->active;
991 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000992 add_redrawwidget(focus);
993
994 if((direction & 1) == 0) {
995 /* Move focus "up" */
996 focus = focus->next;
997 } else {
998 /* Move focus "down" */
999 for(widget = window->active;
1000 widget != NULL; widget = widget->next) {
1001 if(widget->next == focus) {
1002 break;
1003 }
1004 }
1005 focus = widget;
1006 if(focus == NULL) {
1007 if(window->active != NULL) {
1008 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001009 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001010 }
1011 }
1012 }
1013 if(focus == NULL) {
1014 focus = window->active;
1015 }
adamdunkelse0683312003-04-09 09:02:52 +00001016
adamdunkelsb2486562003-04-11 20:22:03 +00001017 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001018}
1019/*-----------------------------------------------------------------------------------*/
1020#if CTK_CONF_MENUS
1021static void
1022switch_open_menu(unsigned char rightleft)
1023{
1024 struct ctk_menu *menu;
1025
1026 if(rightleft == 0) {
1027 /* Move right */
1028 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1029 if(menu->next == menus.open) {
1030 break;
1031 }
1032 }
1033 lastmenu = menus.open;
1034 menus.open = menu;
1035 if(menus.open == NULL) {
1036 for(menu = menus.menus;
1037 menu->next != NULL; menu = menu->next);
1038 menus.open = menu;
1039 }
1040 } else {
1041 /* Move to left */
1042 lastmenu = menus.open;
1043 menus.open = menus.open->next;
1044 if(menus.open == NULL) {
1045 menus.open = menus.menus;
1046 }
1047 }
1048
adamdunkels66109622003-04-24 17:17:10 +00001049 menus.open->active = 0;
1050
1051 /* if(menus.open->nitems > maxnitems) {
1052 maxnitems = menus.open->nitems;
1053 }*/
1054
adamdunkels965e2922003-06-30 20:44:57 +00001055 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001056}
1057/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001058static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001059switch_menu_item(unsigned char updown)
1060{
1061 register struct ctk_menu *m;
1062
1063 m = menus.open;
1064
1065 if(updown == 0) {
1066 /* Move up */
1067 if(m->active == 0) {
1068 m->active = m->nitems - 1;
1069 } else {
1070 --m->active;
1071 if(m->items[m->active].title[0] == '-') {
1072 --m->active;
1073 }
1074 }
1075 } else {
1076 /* Move down */
1077 if(m->active >= m->nitems - 1) {
1078 m->active = 0;
1079 } else {
1080 ++m->active;
1081 if(m->items[m->active].title[0] == '-') {
1082 ++m->active;
1083 }
1084 }
1085 }
1086
1087}
1088#endif /* CTK_CONF_MENUS */
1089/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001090static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001091activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001092{
1093 static unsigned char len;
1094
1095 if(w->type == CTK_WIDGET_BUTTON) {
1096 if(w == (struct ctk_widget *)&windows->closebutton) {
1097#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +00001098 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001099 ctk_window_close(windows);
1100 return REDRAW_ALL;
1101#endif /* CTK_CONF_WINDOWCLOSE */
1102 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1103#if CTK_CONF_WINDOWCLOSE
1104 mode = CTK_MODE_WINDOWMOVE;
1105#endif /* CTK_CONF_WINDOWCLOSE */
1106 } else {
adamdunkels58917a82003-04-18 00:18:38 +00001107 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001108 w->window->owner);
1109 }
1110#if CTK_CONF_ICONS
1111 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +00001112 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001113 w->widget.icon.owner);
1114#endif /* CTK_CONF_ICONS */
1115 } else if(w->type == CTK_WIDGET_HYPERLINK) {
1116 dispatcher_emit(ctk_signal_hyperlink_activate, w,
1117 DISPATCHER_BROADCAST);
1118 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1119 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1120 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1121 len = strlen(w->widget.textentry.text);
1122 if(w->widget.textentry.xpos > len) {
1123 w->widget.textentry.xpos = len;
1124 }
1125 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1126 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +00001127 dispatcher_emit(ctk_signal_widget_activate, w,
1128 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001129 }
1130 add_redrawwidget(w);
1131 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001132 } else {
1133 dispatcher_emit(ctk_signal_widget_activate, w,
1134 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001135 }
1136 return REDRAW_NONE;
1137}
1138/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001139static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001140textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001141 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001142{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001143 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001144 static unsigned char len, txpos, typos, tlen;
1145
1146 txpos = t->xpos;
1147 typos = t->ypos;
1148 tlen = t->len;
1149
1150 cptr = &t->text[txpos + typos * tlen];
1151
1152 switch(c) {
1153 case CH_CURS_LEFT:
1154 if(txpos > 0) {
1155 --txpos;
1156 }
1157 break;
1158
1159 case CH_CURS_RIGHT:
1160 if(txpos < tlen &&
1161 *cptr != 0) {
1162 ++txpos;
1163 }
1164 break;
1165
1166 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001167 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001168 break;
1169
1170 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001171 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001172 break;
1173
1174 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001175 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1176 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001177 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001178 break;
1179
adamdunkels9795b2e2003-08-09 23:32:37 +00001180 case CTK_CONF_WIDGETDOWN_KEY:
1181 t->state = CTK_TEXTENTRY_NORMAL;
1182 switch_focus_widget(DOWN);
1183 break;
1184 case CTK_CONF_WIDGETUP_KEY:
1185 t->state = CTK_TEXTENTRY_NORMAL;
1186 switch_focus_widget(UP);
1187 break;
1188
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001189 default:
1190 len = tlen - txpos - 1;
1191 if(c == CH_DEL) {
1192 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +00001193 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001194 *(cptr + len - 1) = 0;
1195 --txpos;
1196 }
1197 } else {
1198 if(len > 0) {
1199 cptr2 = cptr + len - 1;
1200 while(cptr2 + 1 > cptr) {
1201 *(cptr2 + 1) = *cptr2;
1202 --cptr2;
1203 }
1204
1205 *cptr = c;
1206 ++txpos;
1207 }
1208 }
1209 break;
1210 }
1211
1212 t->xpos = txpos;
1213 t->ypos = typos;
1214}
1215/*-----------------------------------------------------------------------------------*/
1216#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001217static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001218activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001219{
1220 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001221
adamdunkelsb2486562003-04-11 20:22:03 +00001222 lastmenu = menus.open;
1223 if(menus.open == &desktopmenu) {
1224 for(w = windows; w != NULL; w = w->next) {
1225 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1226 ctk_window_open(w);
1227 menus.open = NULL;
1228 return REDRAW_ALL;
1229 }
1230 }
1231 } else {
1232 dispatcher_emit(ctk_signal_menu_activate, menus.open,
1233 DISPATCHER_BROADCAST);
1234 }
1235 menus.open = NULL;
1236 return REDRAW_MENUPART;
1237}
1238/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001239static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001240menus_input(ctk_arch_key_t c)
1241{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001242
1243 if(menus.open->nitems > maxnitems) {
1244 maxnitems = menus.open->nitems;
1245 }
1246
1247
1248 switch(c) {
1249 case CH_CURS_RIGHT:
1250 switch_open_menu(1);
1251
1252 return REDRAW_MENUPART;
1253
1254 case CH_CURS_DOWN:
1255 switch_menu_item(1);
1256 return REDRAW_MENUS;
1257
1258 case CH_CURS_LEFT:
1259 switch_open_menu(0);
1260 return REDRAW_MENUPART;
1261
1262 case CH_CURS_UP:
1263 switch_menu_item(0);
1264 return REDRAW_MENUS;
1265
1266 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001267 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001268
adamdunkels88ed9c42003-03-28 12:10:09 +00001269 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001270 lastmenu = menus.open;
1271 menus.open = NULL;
1272 return REDRAW_MENUPART;
1273 }
adamdunkelsb2486562003-04-11 20:22:03 +00001274
1275 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001276}
1277#endif /* CTK_CONF_MENUS */
1278/*-----------------------------------------------------------------------------------*/
1279static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001280timer(void)
1281{
1282 if(mode == CTK_MODE_NORMAL) {
1283 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001284 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001285#if CTK_CONF_SCREENSAVER
1286 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1287 DISPATCHER_BROADCAST);
1288#ifdef CTK_SCREENSAVER_INIT
1289 CTK_SCREENSAVER_INIT();
1290#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001291
adamdunkelscf90b0d2003-08-09 13:34:16 +00001292#endif /* CTK_CONF_SCREENSAVER */
1293 screensaver_timer = 0;
1294 }
1295 }
1296}
1297/*-----------------------------------------------------------------------------------*/
1298static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001299unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1300{
1301 if(w != NULL) {
1302 redraw |= REDRAW_WIDGETS;
1303 add_redrawwidget(w);
1304 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1305 ((struct ctk_textentry *)w)->state =
1306 CTK_TEXTENTRY_NORMAL;
1307 }
1308 w->window->focused = NULL;
1309 }
1310}
1311/*-----------------------------------------------------------------------------------*/
1312static void
adamdunkelsc4902862003-04-09 00:30:45 +00001313ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001314{
1315 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001316 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001317 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001318 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001319 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001320#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001321 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1322 mouse_clicked;
1323 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001324 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001325
adamdunkels19a787c2003-04-09 09:22:24 +00001326#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001327
1328
1329 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001330
adamdunkels9795b2e2003-08-09 23:32:37 +00001331 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001332 timer();
1333 start = current;
1334 }
1335
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001336#if CTK_CONF_MENUS
1337 if(menus.open != NULL) {
1338 maxnitems = menus.open->nitems;
1339 } else {
1340 maxnitems = 0;
1341 }
1342#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001343
1344#if CTK_CONF_MOUSE_SUPPORT
1345 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1346
1347 /* See if there is any change in the buttons. */
1348 if(ctk_mouse_button() != mouse_button) {
1349 mouse_button = ctk_mouse_button();
1350 mouse_button_changed = 1;
1351 if(mouse_button == 0) {
1352 mouse_clicked = 1;
1353 }
1354 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001355
adamdunkelsb2486562003-04-11 20:22:03 +00001356 /* Check if the mouse pointer has moved. */
1357 if(ctk_mouse_x() != mouse_x ||
1358 ctk_mouse_y() != mouse_y) {
1359 mouse_x = ctk_mouse_x();
1360 mouse_y = ctk_mouse_y();
1361 mouse_moved = 1;
1362 }
1363
1364 mxc = ctk_mouse_xtoc(mouse_x);
1365 myc = ctk_mouse_ytoc(mouse_y);
1366#endif /* CTK_CONF_MOUSE_SUPPORT */
1367
1368
adamdunkels66109622003-04-24 17:17:10 +00001369#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001370 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001371 if(ctk_arch_keyavail()
1372#if CTK_CONF_MOUSE_SUPPORT
1373 || mouse_moved || mouse_button_changed
1374#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001375 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001376 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1377 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001378 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001379 }
adamdunkels66109622003-04-24 17:17:10 +00001380 } else
1381#endif /* CTK_CONF_SCREENSAVER */
1382 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001383#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001384 /* If there is any change in the mouse conditions, find out in
1385 which window the mouse pointer currently is in order to send
1386 the correct signals, or bring a window to focus. */
1387 if(mouse_moved || mouse_button_changed) {
1388 ctk_mouse_show();
1389 screensaver_timer = 0;
1390
1391 if(myc == 0) {
1392 /* Here we should do whatever needs to be done when the mouse
1393 moves around and clicks in the menubar. */
1394 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001395 static unsigned char titlelen;
1396
adamdunkelsb2486562003-04-11 20:22:03 +00001397 /* Find out which menu that the mouse pointer is in. Start
1398 with the ->next menu after the desktop menu. We assume
1399 that the menus start one character from the left screen
1400 side and that the desktop menu is farthest to the
1401 right. */
1402 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001403 for(menu = menus.menus->next;
1404 menu != NULL; menu = menu->next) {
1405 titlelen = menu->titlelen;
1406 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001407 break;
adamdunkelse0683312003-04-09 09:02:52 +00001408 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001409 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001410 }
adamdunkelsb2486562003-04-11 20:22:03 +00001411
1412 /* Also check desktop menu. */
1413 if(mxc >= width - 7 &&
1414 mxc <= width - 1) {
1415 menu = &desktopmenu;
1416 }
1417
1418 menus.open = menu;
1419 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001420 }
adamdunkelse0683312003-04-09 09:02:52 +00001421 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001422 --myc;
1423
1424 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001425 static unsigned char nitems;
1426
adamdunkelsb2486562003-04-11 20:22:03 +00001427 /* Do whatever needs to be done when a menu is open. */
1428
adamdunkelscf90b0d2003-08-09 13:34:16 +00001429 /* First check if the mouse pointer is in the currently open
1430 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001431 if(menus.open == &desktopmenu) {
1432 menux = width - CTK_CONF_MENUWIDTH;
1433 } else {
1434 menux = 1;
1435 for(menu = menus.menus->next; menu != menus.open;
1436 menu = menu->next) {
1437 menux += menu->titlelen;
1438 }
1439 }
1440
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001441 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001442 /* Find out which of the menu items the mouse is pointing
1443 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001444 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1445 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001446 menus.open->active = myc;
1447 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001448 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001449 }
adamdunkelsb2486562003-04-11 20:22:03 +00001450 }
1451
1452 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001453 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001454 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001455 redraw |= activate_menu();
1456 } else {
1457 lastmenu = menus.open;
1458 menus.open = NULL;
1459 redraw |= REDRAW_MENUPART;
1460 }
1461 } else {
1462 redraw |= REDRAW_MENUS;
1463 }
1464 } else {
1465
adamdunkels965e2922003-06-30 20:44:57 +00001466 /* Walk through the windows from top to bottom to see in
1467 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001468 if(dialog != NULL) {
1469 window = dialog;
1470 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001471 for(window = windows; window != NULL;
1472 window = window->next) {
1473
adamdunkelsb2486562003-04-11 20:22:03 +00001474 /* Check if the mouse is within the window. */
1475 if(mxc >= window->x &&
1476 mxc <= window->x + window->w &&
1477 myc >= window->y &&
1478 myc <= window->y + window->h) {
1479 break;
1480 }
1481 }
1482 }
1483
1484
1485 /* If we didn't find any window, and there are no windows
1486 open, the mouse pointer will definately be within the
1487 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001488 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001489 window = &desktop_window;
1490 }
1491
adamdunkels965e2922003-06-30 20:44:57 +00001492 /* If the mouse pointer moves around outside of the
1493 currently focused window (or dialog), we should not have
1494 any focused widgets in the focused window so we make sure
1495 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001496 if(windows != NULL &&
1497 window != windows &&
1498 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001499 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001500 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001501 redraw |= REDRAW_WIDGETS;*/
1502 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001503 }
1504
1505 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001506 /* If the mouse was clicked outside of the current window,
1507 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001508 if(dialog == NULL &&
1509 window != &desktop_window &&
1510 window != windows &&
1511 mouse_clicked) {
1512 /* Bring window to front. */
1513 ctk_window_open(window);
1514 redraw |= REDRAW_ALL;
1515 } else {
1516
adamdunkels965e2922003-06-30 20:44:57 +00001517 /* Find out which widget currently is under the mouse
1518 pointer and give it focus, unless it already has
1519 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001520 mxc = mxc - window->x - 1;
1521 myc = myc - window->y - 1;
1522
adamdunkels965e2922003-06-30 20:44:57 +00001523 /* See if the mouse pointer is on a widget. If so, it
1524 should be selected and, if the button is clicked,
1525 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001526 for(widget = window->active; widget != NULL;
1527 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001528
adamdunkelsb2486562003-04-11 20:22:03 +00001529 if(mxc >= widget->x &&
1530 mxc <= widget->x + widget->w &&
1531 (myc == widget->y ||
1532 ((widget->type == CTK_WIDGET_BITMAP ||
1533 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1534 widget->type == CTK_WIDGET_ICON) &&
1535 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001536 myc <= widget->y +
1537 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001538 break;
1539 }
1540 }
1541
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001542
1543 /* if the mouse is moved in the focused window, we emit
1544 a ctk_signal_pointer_move signal to the owner of the
1545 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001546 if(mouse_moved &&
1547 (window != &desktop_window ||
1548 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001549
adamdunkelsb2486562003-04-11 20:22:03 +00001550 dispatcher_emit(ctk_signal_pointer_move, NULL,
1551 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552
1553 /* If there was a focused widget that is not below the
1554 mouse pointer, we remove focus from the widget and
1555 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001556 if(window->focused != NULL &&
1557 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001558 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001559 if(CTK_WIDGET_TYPE(window->focused) ==
1560 CTK_WIDGET_TEXTENTRY) {
1561 ((struct ctk_textentry *)(window->focused))->state =
1562 CTK_TEXTENTRY_NORMAL;
1563 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001564 window->focused = NULL;*/
1565 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001566 }
1567 redraw |= REDRAW_WIDGETS;
1568 if(widget != NULL) {
1569 select_widget(widget);
1570 }
1571 }
1572
1573 if(mouse_button_changed) {
1574 dispatcher_emit(ctk_signal_pointer_button,
1575 (ek_data_t)mouse_button,
1576 window->owner);
1577 if(mouse_clicked && widget != NULL) {
1578 select_widget(widget);
1579 redraw |= activate(widget);
1580 }
1581 }
1582 }
1583 }
1584 }
adamdunkelsc4902862003-04-09 00:30:45 +00001585 }
1586 }
adamdunkels19a787c2003-04-09 09:22:24 +00001587#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001588
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001589 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001590
1591 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001592
1593 screensaver_timer = 0;
1594
adamdunkelsb2486562003-04-11 20:22:03 +00001595 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001596
1597 if(dialog != NULL) {
1598 window = dialog;
1599 } else if(windows != NULL) {
1600 window = windows;
1601 } else {
1602 window = &desktop_window;
1603 }
1604 widget = window->focused;
1605
1606
1607 if(widget != NULL &&
1608 widget->type == CTK_WIDGET_TEXTENTRY &&
1609 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1610 textentry_input(c, (struct ctk_textentry *)widget);
1611 add_redrawwidget(widget);
1612#if CTK_CONF_MENUS
1613 } else if(menus.open != NULL) {
1614 redraw |= menus_input(c);
1615#endif /* CTK_CONF_MENUS */
1616 } else {
1617 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001618 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001619 switch_focus_widget(DOWN);
1620 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001621 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001622 switch_focus_widget(UP);
1623 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001624#if CTK_CONF_MENUS
1625 case CTK_CONF_MENU_KEY:
1626 if(dialog == NULL) {
1627 if(lastmenu == NULL) {
1628 menus.open = menus.menus;
1629 } else {
1630 menus.open = lastmenu;
1631 }
1632 menus.open->active = 0;
1633 redraw |= REDRAW_MENUS;
1634 }
1635 break;
1636#endif /* CTK_CONF_MENUS */
1637 case CTK_CONF_WINDOWSWITCH_KEY:
1638 if(windows != NULL) {
1639 for(window = windows; window->next != NULL;
1640 window = window->next);
1641 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001642 }
1643 break;
1644 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001645 if(c == CH_ENTER &&
1646 widget != NULL) {
1647 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001648 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001649 if(widget != NULL &&
1650 widget->type == CTK_WIDGET_TEXTENTRY) {
1651 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1652 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001653 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001654 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001655 /* window->focused = NULL;*/
1656 unfocus_widget(window->focused);
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001657 dispatcher_fastemit(ctk_signal_keypress, (void *)c,
1658 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001659 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001660 }
1661 break;
1662 }
1663 }
1664
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001665#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001666 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001667 widgetptr = redraw_widgets;
1668 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001669 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001670 *widgetptr = NULL;
1671 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001672 }
1673 redraw &= ~REDRAW_WIDGETS;
1674 redraw_widgetptr = 0;
1675 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001676#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001677 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001678#if CTK_CONF_WINDOWMOVE
1679 } else if(mode == CTK_MODE_WINDOWMOVE) {
1680
1681 redraw = 0;
1682
1683 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001684
1685#if CTK_CONF_MOUSE_SUPPORT
1686
1687 /* If the mouse has moved, we move the window as well. */
1688 if(mouse_moved) {
1689
1690 if(window->w + mxc + 2 >= width) {
1691 window->x = width - 2 - window->w;
1692 } else {
1693 window->x = mxc;
1694 }
1695
1696 if(window->h + myc + 2 >= height) {
1697 window->y = height - 2 - window->h;
1698 } else {
1699 window->y = myc;
1700 }
1701 if(window->y > 0) {
1702 --window->y;
1703 }
1704
1705 redraw = REDRAW_ALL;
1706 }
1707
1708 /* Check if the mouse has been clicked, and stop moving the window
1709 if so. */
1710 if(mouse_button_changed &&
1711 mouse_button == 0) {
1712 mode = CTK_MODE_NORMAL;
1713 redraw = REDRAW_ALL;
1714 }
1715#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001716
1717 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1718
1719 screensaver_timer = 0;
1720
1721 c = ctk_arch_getkey();
1722
1723 switch(c) {
1724 case CH_CURS_RIGHT:
1725 ++window->x;
1726 if(window->x + window->w + 1 >= width) {
1727 --window->x;
1728 }
1729 redraw = REDRAW_ALL;
1730 break;
1731 case CH_CURS_LEFT:
1732 if(window->x > 0) {
1733 --window->x;
1734 }
1735 redraw = REDRAW_ALL;
1736 break;
1737 case CH_CURS_DOWN:
1738 ++window->y;
1739 if(window->y + window->h + 2 >= height) {
1740 --window->y;
1741 }
1742 redraw = REDRAW_ALL;
1743 break;
1744 case CH_CURS_UP:
1745 if(window->y > 0) {
1746 --window->y;
1747 }
1748 redraw = REDRAW_ALL;
1749 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001750 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001751 mode = CTK_MODE_NORMAL;
1752 redraw = REDRAW_ALL;
1753 break;
1754 }
1755 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001756#endif /* CTK_CONF_WINDOWMOVE */
1757 }
adamdunkelsb2486562003-04-11 20:22:03 +00001758
1759 if(redraw & REDRAW_ALL) {
1760 do_redraw_all(1, height);
1761#if CTK_CONF_MENUS
1762 } else if(redraw & REDRAW_MENUPART) {
1763 do_redraw_all(1, maxnitems + 1);
1764 } else if(redraw & REDRAW_MENUS) {
1765 ctk_draw_menus(&menus);
1766#endif /* CTK_CONF_MENUS */
1767 } else if(redraw & REDRAW_FOCUS) {
1768 if(dialog != NULL) {
1769 ctk_window_redraw(dialog);
1770 } else if(windows != NULL) {
1771 ctk_window_redraw(windows);
1772 } else {
1773 ctk_window_redraw(&desktop_window);
1774 }
1775 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001776 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001777 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001778 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001779 *widgetptr = NULL;
1780 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001781 }
1782 }
1783 redraw = 0;
1784 redraw_widgetptr = 0;
1785
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001786}
1787/*-----------------------------------------------------------------------------------*/