blob: 1d0bc115fb023e3895ca5aa86570c08a37572826 [file] [log] [blame]
adamdunkels35298692003-08-31 22:16:49 +00001/**
2 * \file
3 * The Contiki Toolkit, CTK, the Contiki GUI.
4 * \author Adam Dunkels <adam@dunkels.com>
5 *
6 * The Contiki Toolkit (CTK) provides the graphical user interface for
7 * the Contiki system.
8 *
9 *
10 */
11
adamdunkelsca9ddcb2003-03-19 14:13:31 +000012/*
adamdunkels35298692003-08-31 22:16:49 +000013 * Copyright (c) 2002-2003, Adam Dunkels.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000014 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
adamdunkels35298692003-08-31 22:16:49 +000025 * 3. The name of the author may not be used to endorse or promote
adamdunkelsca9ddcb2003-03-19 14:13:31 +000026 * products derived from this software without specific prior
27 * written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
30 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * This file is part of the "ctk" console GUI toolkit for cc65
42 *
adamdunkels35298692003-08-31 22:16:49 +000043 * $Id: ctk.c,v 1.31 2003/08/31 22:17:09 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000044 *
45 */
46
adamdunkelsd07a5422003-04-05 12:22:35 +000047#include "cc.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000048#include "ek.h"
49#include "dispatcher.h"
50#include "ctk.h"
51#include "ctk-draw.h"
52#include "ctk-conf.h"
adamdunkelsc4902862003-04-09 00:30:45 +000053#include "ctk-mouse.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000054
adamdunkels591724c2003-08-01 00:07:19 +000055#include <string.h>
56
adamdunkelsca9ddcb2003-03-19 14:13:31 +000057static unsigned char height, width;
58
59static unsigned char mode;
60
61static struct ctk_window desktop_window;
62static struct ctk_window *windows;
63static struct ctk_window *dialog;
64
65#if CTK_CONF_MENUS
66static struct ctk_menus menus;
67static struct ctk_menu *lastmenu;
68static struct ctk_menu desktopmenu;
69#endif /* CTK_CONF_MENUS */
70
71#ifndef NULL
72#define NULL (void *)0
73#endif /* NULL */
74
adamdunkelsca9ddcb2003-03-19 14:13:31 +000075#define REDRAW_NONE 0
76#define REDRAW_ALL 1
77#define REDRAW_FOCUS 2
78#define REDRAW_WIDGETS 4
79#define REDRAW_MENUS 8
80#define REDRAW_MENUPART 16
81
82#define MAX_REDRAWWIDGETS 4
83static unsigned char redraw;
84static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
85static unsigned char redraw_widgetptr;
86static unsigned char maxnitems;
87
88static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000089#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000090#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000091#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000092#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000093#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094
adamdunkelsc4902862003-04-09 00:30:45 +000095static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +000097 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098static ek_id_t ctkid;
99
adamdunkels35298692003-08-31 22:16:49 +0000100ek_signal_t
101
102 /** Emitted for every key being pressed. The key is passed as signal
103 data.*/
104 ctk_signal_keypress,
105
106 /** Emitted when a widget is activated (pressed). A pointer to the
107 widget is passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000108 ctk_signal_widget_activate,
adamdunkels35298692003-08-31 22:16:49 +0000109 /** Same as ctk_signal_widget_activate. */
110 ctk_signal_button_activate,
111
112 /** Emitted when a widget is selected. A pointer to the widget is
113 passed as signal data. */
adamdunkels58917a82003-04-18 00:18:38 +0000114 ctk_signal_widget_select,
adamdunkels35298692003-08-31 22:16:49 +0000115 /** Same as ctk_signal_widget_select. */
116 ctk_signal_button_hover,
117
118 /** Emitted when a hyperlink is activated. The signal is broadcast
119 to all listeners. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000120 ctk_signal_hyperlink_activate,
adamdunkels35298692003-08-31 22:16:49 +0000121
122 /** Same as ctk_signal_widget_select.. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000123 ctk_signal_hyperlink_hover,
adamdunkels35298692003-08-31 22:16:49 +0000124
125 /** Emitted when a menu item is activated. The number of the menu
126 item is passed as signal data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000127 ctk_signal_menu_activate,
adamdunkels35298692003-08-31 22:16:49 +0000128
129 /** Emitted when a window is closed. A pointer to the window is
130 passed as signal data. */
adamdunkelsc4902862003-04-09 00:30:45 +0000131 ctk_signal_window_close,
adamdunkels35298692003-08-31 22:16:49 +0000132
133 /** Emitted when the mouse pointer is moved. A NULL pointer is
134 passed as signal data and it is up to the listening process to
135 check the position of the mouse using the CTK mouse API.*/
adamdunkelsc4902862003-04-09 00:30:45 +0000136 ctk_signal_pointer_move,
adamdunkels35298692003-08-31 22:16:49 +0000137
138 /** Emitted when a mouse button is pressed. The button is passed as
139 signal data to the listening process. */
adamdunkelsb2486562003-04-11 20:22:03 +0000140 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000141
adamdunkels66109622003-04-24 17:17:10 +0000142#if CTK_CONF_SCREENSAVER
adamdunkels9795b2e2003-08-09 23:32:37 +0000143ek_signal_t ctk_signal_screensaver_stop,
144 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000145#endif /* CTK_CONF_SCREENSAVER */
146
147
adamdunkels19a787c2003-04-09 09:22:24 +0000148#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000149unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000150#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000151
adamdunkels9795b2e2003-08-09 23:32:37 +0000152static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000153unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels9795b2e2003-08-09 23:32:37 +0000154static ek_clock_t start, current;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000155
156#if CTK_CONF_MENUS
157/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000158/**
159 * \internal Creates the Desktop menu.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000160 *
161 * Creates the leftmost menu, "Desktop". Since the desktop menu
162 * contains the list of all open windows, this function will be called
163 * whenever a window is opened or closed.
164 */
adamdunkels35298692003-08-31 22:16:49 +0000165/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000166static void
167make_desktopmenu(void)
168{
169 struct ctk_window *w;
170
171 desktopmenu.nitems = 0;
172
173 if(windows == NULL) {
174 ctk_menuitem_add(&desktopmenu, "(No windows)");
175 } else {
176 for(w = windows; w != NULL; w = w->next) {
177 ctk_menuitem_add(&desktopmenu, w->title);
178 }
179 }
180}
181#endif /* CTK_CONF_MENUS */
182/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000183/**
184 * Initializes the Contiki Toolkit.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000185 *
adamdunkels35298692003-08-31 22:16:49 +0000186 * This function must be called before any other CTK function, but
187 * after the inizialitation of the dispatcher module.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000188 */
adamdunkels35298692003-08-31 22:16:49 +0000189/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000190void
191ctk_init(void)
192{
193 ctkid = dispatcher_start(&p);
194
195 windows = NULL;
196 dialog = NULL;
197
198#if CTK_CONF_MENUS
199 ctk_menu_new(&desktopmenu, "Desktop");
200 make_desktopmenu();
201 menus.menus = menus.desktopmenu = &desktopmenu;
202#endif /* CTK_CONF_MENUS */
203
adamdunkelsb2486562003-04-11 20:22:03 +0000204#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000205 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000206 ctk_mouse_show();
207#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000208
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000209 ctk_draw_init();
210
211 height = ctk_draw_height();
212 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000213
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000214 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000215
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000216 ctk_signal_keypress = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000217
218 ctk_signal_button_activate =
219 ctk_signal_widget_activate = dispatcher_sigalloc();
220
221 ctk_signal_button_hover =
222 ctk_signal_hyperlink_hover =
223 ctk_signal_widget_select = dispatcher_sigalloc();
224
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000225 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000226
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227 ctk_signal_menu_activate = dispatcher_sigalloc();
228 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000229
230 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000231 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000232
233
234#if CTK_CONF_SCREENSAVER
235 ctk_signal_screensaver_start = dispatcher_sigalloc();
236 ctk_signal_screensaver_stop = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000237#endif /* CTK_CONF_SCREENSAVER */
238
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000239
240 mode = CTK_MODE_NORMAL;
241
242 iconx = ICONX_START;
243 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000244
245 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000246
247 start = ek_clock();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000248}
249/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000250/**
251 * Sets the current CTK mode.
252 *
253 * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
254 * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
255 * keypresses and mouse pointer movements are processed and the screen
256 * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
257 * performed and the first key press or pointer movement will cause
258 * the ctk_signal_screensaver_stop to be emitted. In the
259 * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
260 * ignored and no screen redraws are made.
261 *
262 * \param m The mode.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263 */
adamdunkels35298692003-08-31 22:16:49 +0000264/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000265void
266ctk_mode_set(unsigned char m) {
267 mode = m;
268}
269/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000270/**
271 * Retrieves the current CTK mode.
272 *
273 * \return The current CTK mode.
274 */
275/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000276unsigned char
277ctk_mode_get(void) {
278 return mode;
279}
280/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000281/**
282 * Add an icon to the desktop.
283 *
284 * \param icon The icon to be added.
285 */
286/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000287void
adamdunkels35298692003-08-31 22:16:49 +0000288ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000289{
290#if CTK_CONF_ICONS
291 icon->x = iconx;
292 icon->y = icony;
adamdunkels35298692003-08-31 22:16:49 +0000293 icon->widget.icon.owner = DISPATCHER_CURRENT();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000294
295 icony += ICONY_DELTA;
296 if(icony >= ICONY_MAX) {
297 icony = ICONY_START;
298 iconx += ICONX_DELTA;
299 }
300
301 ctk_widget_add(&desktop_window, icon);
302#endif /* CTK_CONF_ICONS */
303}
304/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000305/**
306 * Open a dialog box.
307 *
308 * \param d The dialog to be opened.
309 */
310/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000311void
312ctk_dialog_open(struct ctk_window *d)
313{
314 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000315 redraw |= REDRAW_FOCUS;
adamdunkels35298692003-08-31 22:16:49 +0000316}
317/*-----------------------------------------------------------------------------------*/
318/**
319 * Close the dialog box, if one is open.
320 *
321 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322/*-----------------------------------------------------------------------------------*/
323void
324ctk_dialog_close(void)
325{
326 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000327 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000328}
329/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000330/**
331 * Open a window, or bring window to front if already open.
332 *
333 * \param w The window to be opened.
334 */
335/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000336void
adamdunkelsd07a5422003-04-05 12:22:35 +0000337ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000338{
339 struct ctk_window *w2;
340
341 /* Check if already open. */
342 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
343 if(w2 == NULL) {
344 /* Not open, so we add it at the head of the list of open
345 windows. */
346 w->next = windows;
347 if(windows != NULL) {
348 windows->prev = w;
349 }
350 windows = w;
351 w->prev = NULL;
352 } else {
353 /* Window already open, so we move it to the front of the windows
354 list. */
355 if(w != windows) {
356 if(w->next != NULL) {
357 w->next->prev = w->prev;
358 }
359 if(w->prev != NULL) {
360 w->prev->next = w->next;
361 }
362 w->next = windows;
363 windows->prev = w;
364 windows = w;
365 w->prev = NULL;
366 }
367 }
368
369#if CTK_CONF_MENUS
370 /* Recreate the Desktop menu's window entries.*/
371 make_desktopmenu();
372#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000373
374 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000375}
376/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000377/**
378 * Close a window if it is open.
379 *
380 * If the window is not open, this function does nothing.
381 *
382 * \param w The window to be closed.
383 */
384/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000385void
386ctk_window_close(struct ctk_window *w)
387{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000388 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000389
390 if(w == NULL) {
391 return;
392 }
393
394 /* Check if the window to be closed is the first window on the
395 list. */
396 if(w == windows) {
397 windows = w->next;
398 if(windows != NULL) {
399 windows->prev = NULL;
400 }
401 w->next = w->prev = NULL;
402 } else {
403 /* Otherwise we step through the list until we find the window
404 before the one to be closed. We then redirect its ->next
405 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000406 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
407
408 if(w2 == NULL) {
409 /* The window wasn't open, so there is nothing more for us to
410 do. */
411 return;
412 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000413
414 if(w->next != NULL) {
415 w->next->prev = w->prev;
416 }
417 w2->next = w->next;
418
419 w->next = w->prev = NULL;
420 }
421
422#if CTK_CONF_MENUS
423 /* Recreate the Desktop menu's window entries.*/
424 make_desktopmenu();
425#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000426 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000427}
428/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000429/**
430 * \internal Create the move and close buttons on the window titlebar.
431 */
432/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000433static void
434make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000435{
436#if CTK_CONF_WINDOWMOVE
437 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
438#else
439 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
440#endif /* CTK_CONF_WINDOWMOVE */
441 CTK_WIDGET_ADD(window, &window->titlebutton);
442
443
444#if CTK_CONF_WINDOWCLOSE
445 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
446#else
447 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
448#endif /* CTK_CONF_WINDOWCLOSE */
449 CTK_WIDGET_ADD(window, &window->closebutton);
450}
451/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000452/**
453 * Remove all widgets from a window.
454 *
455 * \param w The window to be cleared.
456 */
457/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458void
adamdunkels35298692003-08-31 22:16:49 +0000459ctk_window_clear(struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000460{
adamdunkels35298692003-08-31 22:16:49 +0000461 w->active = w->inactive = w->focused = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000462
adamdunkels35298692003-08-31 22:16:49 +0000463 make_windowbuttons(w);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000464}
465/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000466/**
467 * Add a menu to the menu bar.
468 *
469 * \param menu The menu to be added.
470 *
471 * \note Do not call this function multiple times for the same menu,
472 * as no check is made to see if the menu already is in the menu bar.
473 */
474/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000475void
476ctk_menu_add(struct ctk_menu *menu)
477{
478#if CTK_CONF_MENUS
479 struct ctk_menu *m;
480
481 if(lastmenu == NULL) {
482 lastmenu = menu;
483 }
484
485 for(m = menus.menus; m->next != NULL; m = m->next) {
486 if(m == menu) {
487 return;
488 }
489 }
490 m->next = menu;
491 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000492
493 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000494#endif /* CTK_CONF_MENUS */
495}
496/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000497/**
498 * Remove a menu from the menu bar.
499 *
500 * \param menu The menu to be removed.
501 */
502/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000503void
504ctk_menu_remove(struct ctk_menu *menu)
505{
506#if CTK_CONF_MENUS
507 struct ctk_menu *m;
508
509 for(m = menus.menus; m->next != NULL; m = m->next) {
510 if(m->next == menu) {
511 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000512 if(menu == lastmenu) {
513 lastmenu = NULL;
514 }
515 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000516 return;
517 }
518 }
519#endif /* CTK_CONF_MENUS */
520}
521/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000522/**
523 * \internal Redraws everything on the screen within the clip
524 * interval.
525 *
526 * \param clipy1 The upper bound of the clip interval
527 * \param clipy2 The lower bound of the clip interval
528 */
529/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000530static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000531do_redraw_all(unsigned char clipy1, unsigned char clipy2)
532{
533 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000534 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000535
536 if(mode != CTK_MODE_NORMAL &&
537 mode != CTK_MODE_WINDOWMOVE) {
538 return;
539 }
540
541 ctk_draw_clear(clipy1, clipy2);
542
543 /* Draw widgets in root window */
544 for(widget = desktop_window.active;
545 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000546 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000547 }
548
549 /* Draw windows */
550 if(windows != NULL) {
551 /* Find the last window.*/
552 for(w = windows; w->next != NULL; w = w->next);
553
554 /* Draw the windows from back to front. */
555 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000556 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000557 ctk_draw_window(w, 0, clipy1, clipy2);
558 }
559 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000560 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000561 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
562 }
563
564 /* Draw dialog (if any) */
565 if(dialog != NULL) {
566 ctk_draw_dialog(dialog);
567 }
568
569#if CTK_CONF_MENUS
570 ctk_draw_menus(&menus);
571#endif /* CTK_CONF_MENUS */
572}
573/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000574/**
575 * Redraw the entire desktop.
576 *
577 * \param d The desktop to be redrawn.
578 *
579 * \note Currently the parameter d is not used, but must be set to
580 * NULL.
581 */
582/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000583void
adamdunkels965e2922003-06-30 20:44:57 +0000584ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000585{
586 if(DISPATCHER_CURRENT() == ctkid) {
587 if(mode == CTK_MODE_NORMAL ||
588 mode == CTK_MODE_WINDOWMOVE) {
589 do_redraw_all(1, height);
590 }
591 } else {
592 redraw |= REDRAW_ALL;
593 }
594}
595/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000596/**
597 * Redraw a window.
598 *
599 * This function redraws the window, but only if it is the foremost
600 * one on the desktop.
601 *
602 * \param w The window to be redrawn.
603 */
604/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000605void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000606ctk_window_redraw(struct ctk_window *w)
607{
608 /* Only redraw the window if it is a dialog or if it is the foremost
609 window. */
610 if(mode != CTK_MODE_NORMAL) {
611 return;
612 }
613
614 if(w == dialog) {
615 ctk_draw_dialog(w);
616 } else if(dialog == NULL &&
617#if CTK_CONF_MENUS
618 menus.open == NULL &&
619#endif /* CTK_CONF_MENUS */
620 windows == w) {
621 ctk_draw_window(w, CTK_FOCUS_WINDOW,
622 0, height);
623 }
624}
625/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000626/**
627 * \internal Creates a new window.
628 *
629 * \param window The window to be created.
630 * \param w The width of the window.
631 * \param h The height of the window.
632 * \param title The title of the window.
633 */
634/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000635static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000636window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000637 unsigned char w, unsigned char h,
638 char *title)
639{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000640
641 if(w >= width - 2) {
642 window->x = 0;
643 } else {
644 window->x = (width - w - 2) / 2;
645 }
646 if(h >= height - 3) {
647 window->y = 0;
648 } else {
649 window->y = (height - h - 1) / 2;
650 }
651
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000652 window->w = w;
653 window->h = h;
654 window->title = title;
655 if(title != NULL) {
656 window->titlelen = strlen(title);
657 } else {
658 window->titlelen = 0;
659 }
660 window->next = window->prev = NULL;
661 window->owner = DISPATCHER_CURRENT();
662 window->active = window->inactive = window->focused = NULL;
663}
664/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000665/**
666 * Create a new window.
667 *
668 * Creates a new window. The memory for the window structure must
669 * already be allocated by the caller, and is usually done with a
670 * static declaration.
671 *
672 * This function sets up the internal structure of the ctk_window
673 * struct and creates the move and close buttons, but it does not open
674 * the window. The window must be explicitly opened by calling the
675 * ctk_window_open() function.
676 *
677 * \param window The window to be created.
678 * \param w The width of the new window.
679 * \param h The height of the new window.
680 * \param title The title of the new window.
681 */
682/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000683void
684ctk_window_new(struct ctk_window *window,
685 unsigned char w, unsigned char h,
686 char *title)
687{
688 window_new(window, w, h, title);
689
690 make_windowbuttons(window);
691}
692/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000693/**
694 * Creates a new dialog.
695 *
696 * This function only sets up the internal structure of the ctk_window
697 * struct but does not open the dialog. The dialog must be explicitly
698 * opened by calling the ctk_dialog_open() function.
699 *
700 * \param dialog The dialog to be created.
701 * \param w The width of the dialog.
702 * \param h The height of the dialog.
703 */
704/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000705void
adamdunkels35298692003-08-31 22:16:49 +0000706ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000707 unsigned char w, unsigned char h)
708{
adamdunkels35298692003-08-31 22:16:49 +0000709 window_new(dialog, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000710}
adamdunkels3af580f2003-08-11 22:27:13 +0000711/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000712/**
713 * Creates a new menu.
714 *
715 * This function sets up the internal structure of the menu, but does
716 * not add it to the menubar. Use the function ctk_menu_add() for that
717 * purpose.
718 *
719 * \param menu The menu to be created.
720 * \param title The title of the menu.
721 */
722/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000723void
adamdunkelsd07a5422003-04-05 12:22:35 +0000724ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000725 char *title)
726{
727#if CTK_CONF_MENUS
728 menu->next = NULL;
729 menu->title = title;
730 menu->titlelen = strlen(title);
731 menu->active = 0;
732 menu->nitems = 0;
733#endif /* CTK_CONF_MENUS */
734}
735/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000736/**
737 * Adds a menu item to a menu.
738 *
739 * In CTK, each menu item is identified by a number which is unique
740 * within each menu. When a menu item is selected, a
741 * ctk_menuitem_activated signal is emitted and the menu item number
742 * is passed as signal data with the signal.
743 *
744 * \param menu The menu to which the menu item should be added.
745 * \param name The name of the menu item.
746 * \return The number of the menu item.
747 */
748/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000749unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000750ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000751 char *name)
752{
753#if CTK_CONF_MENUS
754 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
755 return 0;
756 }
757 menu->items[menu->nitems].title = name;
758 menu->items[menu->nitems].titlelen = strlen(name);
759 return menu->nitems++;
760#else
761 return 0;
762#endif /* CTK_CONF_MENUS */
763}
764/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000765/**
766 * \internal Adds a widget to the list of widgets that should be
767 * redrawn.
768 *
769 * \param w The widget that should be redrawn.
770 */
771/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000772static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000773add_redrawwidget(struct ctk_widget *w)
774{
775 static unsigned char i;
776
777 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
778 redraw |= REDRAW_FOCUS;
779 } else {
780 redraw |= REDRAW_WIDGETS;
781 /* Check if it is in the queue already. If so, we don't add it
782 again. */
783 for(i = 0; i < redraw_widgetptr; ++i) {
784 if(redraw_widgets[i] == w) {
785 return;
786 }
787 }
788 redraw_widgets[redraw_widgetptr++] = w;
789 }
790}
791/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000792/**
793 * \internal Checks if a widget redrawn and adds it to the list of
794 * widgets to be redrawn.
795 *
796 * A widget can be redrawn only if the current CTK mode is
797 * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
798 * foremost window.
799 *
800 * \param widget The widget that should be redrawn.
801 */
802/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000803static void
804widget_redraw(struct ctk_widget *widget)
805{
806 struct ctk_window *window;
807
808 if(mode != CTK_MODE_NORMAL || widget == NULL) {
809 return;
810 }
811
812 /* Only redraw widgets that are in the foremost window. If we would
813 allow redrawing widgets in non-focused windows, we would have to
814 redraw all the windows that cover the non-focused window as well,
815 which would lead to flickering.
816
817 Also, we avoid drawing any widgets when the menus are active.
818 */
819
820#if CTK_CONF_MENUS
821 if(menus.open == NULL)
822#endif /* CTK_CONF_MENUS */
823 {
824 window = widget->window;
825 if(window == dialog) {
826 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
827 } else if(dialog == NULL &&
828 (window == windows ||
829 window == &desktop_window)) {
830 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
831 }
832 }
833}
834/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000835/**
836 * Redraws a widget.
837 *
838 * This function will set a flag which causes the widget to be redrawn
839 * next time the CTK process is scheduled.
840 *
841 * \param widget The widget that is to be redrawn.
842 *
843 * \note This function should usually not be called directly since it
844 * requires typecasting of the widget parameter. The wrapper macro
845 * CTK_WIDGET_REDRAW() does the required typecast and should be used
846 * instead.
847 */
848/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000849void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000850ctk_widget_redraw(struct ctk_widget *widget)
851{
852 struct ctk_window *window;
853
adamdunkels9f667f22003-04-16 18:29:19 +0000854 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000855 return;
856 }
857
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000858 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000859 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000860 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000861}
862/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000863/**
864 * Adds a widget to a window.
865 *
866 * This function adds a widget to a window. The order of which the
867 * widgets are added is important, as it sets the order to which
868 * widgets are cycled with the widget selection keys.
869 *
870 * \param window The window to which the widhet should be added.
871 * \param widget The widget to be added.
872 */
873/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000874void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000875ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
876 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000877{
878 if(widget->type == CTK_WIDGET_LABEL ||
879 widget->type == CTK_WIDGET_SEPARATOR) {
880 widget->next = window->inactive;
881 window->inactive = widget;
882 widget->window = window;
883 } else {
884 widget->next = window->active;
885 window->active = widget;
886 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000887 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000888 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000889 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000890 }
891}
892/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000893/**
894 * Gets the width of the desktop.
895 *
896 * \param d The desktop.
897 * \return The width of the desktop, in characters.
898 *
899 * \note The d parameter is currently unused and must be set to NULL.
900 */
901/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000902unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000903ctk_desktop_width(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000904{
905 return ctk_draw_width();
906}
907/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000908/**
909 * Gets the height of the desktop.
910 *
911 * \param d The desktop.
912 * \return The height of the desktop, in characters.
913 *
914 * \note The d parameter is currently unused and must be set to NULL.
915 */
916/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000917unsigned char
adamdunkels35298692003-08-31 22:16:49 +0000918ctk_desktop_height(struct ctk_desktop *d)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000919{
920 return ctk_draw_height();
921}
922/*-----------------------------------------------------------------------------------*/
adamdunkels35298692003-08-31 22:16:49 +0000923/**
924 * \internal Selects a widget in the window of the widget.
925 *
926 * \param focus The widget to be focused.
927 */
928/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000929static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000930select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000931{
932 struct ctk_window *window;
933
934 window = focus->window;
935
936 if(focus != window->focused) {
937 window->focused = focus;
938 /* The operation changed the focus, so we emit a "hover" signal
939 for those widgets that support it. */
940
941 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
942 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
943 window->owner);
944 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
945 dispatcher_emit(ctk_signal_button_hover, window->focused,
946 window->owner);
947 }
948
949 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000950
951 dispatcher_emit(ctk_signal_widget_select, focus,
952 focus->window->owner);
953
adamdunkelse0683312003-04-09 09:02:52 +0000954 }
955
956}
957/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958#define UP 0
959#define DOWN 1
960#define LEFT 2
961#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000962static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000963switch_focus_widget(unsigned char direction)
964{
965 register struct ctk_window *window;
966 register struct ctk_widget *focus;
967 struct ctk_widget *widget;
968
969
970 if(dialog != NULL) {
971 window = dialog;
972 } else {
973 window = windows;
974 }
975
976 /* If there are no windows open, we move focus around between the
977 icons on the root window instead. */
978 if(window == NULL) {
979 window = &desktop_window;
980 }
981
982 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000983 if(focus == NULL) {
984 focus = window->active;
985 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986 add_redrawwidget(focus);
987
988 if((direction & 1) == 0) {
989 /* Move focus "up" */
990 focus = focus->next;
991 } else {
992 /* Move focus "down" */
993 for(widget = window->active;
994 widget != NULL; widget = widget->next) {
995 if(widget->next == focus) {
996 break;
997 }
998 }
999 focus = widget;
1000 if(focus == NULL) {
1001 if(window->active != NULL) {
1002 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +00001003 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001004 }
1005 }
1006 }
1007 if(focus == NULL) {
1008 focus = window->active;
1009 }
adamdunkelse0683312003-04-09 09:02:52 +00001010
adamdunkelsb2486562003-04-11 20:22:03 +00001011 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001012}
1013/*-----------------------------------------------------------------------------------*/
1014#if CTK_CONF_MENUS
1015static void
1016switch_open_menu(unsigned char rightleft)
1017{
1018 struct ctk_menu *menu;
1019
1020 if(rightleft == 0) {
1021 /* Move right */
1022 for(menu = menus.menus; menu != NULL; menu = menu->next) {
1023 if(menu->next == menus.open) {
1024 break;
1025 }
1026 }
1027 lastmenu = menus.open;
1028 menus.open = menu;
1029 if(menus.open == NULL) {
1030 for(menu = menus.menus;
1031 menu->next != NULL; menu = menu->next);
1032 menus.open = menu;
1033 }
1034 } else {
1035 /* Move to left */
1036 lastmenu = menus.open;
1037 menus.open = menus.open->next;
1038 if(menus.open == NULL) {
1039 menus.open = menus.menus;
1040 }
1041 }
1042
adamdunkels66109622003-04-24 17:17:10 +00001043 menus.open->active = 0;
1044
1045 /* if(menus.open->nitems > maxnitems) {
1046 maxnitems = menus.open->nitems;
1047 }*/
1048
adamdunkels965e2922003-06-30 20:44:57 +00001049 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001050}
1051/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +00001052static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001053switch_menu_item(unsigned char updown)
1054{
1055 register struct ctk_menu *m;
1056
1057 m = menus.open;
1058
1059 if(updown == 0) {
1060 /* Move up */
1061 if(m->active == 0) {
1062 m->active = m->nitems - 1;
1063 } else {
1064 --m->active;
1065 if(m->items[m->active].title[0] == '-') {
1066 --m->active;
1067 }
1068 }
1069 } else {
1070 /* Move down */
1071 if(m->active >= m->nitems - 1) {
1072 m->active = 0;
1073 } else {
1074 ++m->active;
1075 if(m->items[m->active].title[0] == '-') {
1076 ++m->active;
1077 }
1078 }
1079 }
1080
1081}
1082#endif /* CTK_CONF_MENUS */
1083/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001084static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +00001085activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001086{
1087 static unsigned char len;
1088
1089 if(w->type == CTK_WIDGET_BUTTON) {
1090 if(w == (struct ctk_widget *)&windows->closebutton) {
1091#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +00001092 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001093 ctk_window_close(windows);
1094 return REDRAW_ALL;
1095#endif /* CTK_CONF_WINDOWCLOSE */
1096 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
1097#if CTK_CONF_WINDOWCLOSE
1098 mode = CTK_MODE_WINDOWMOVE;
1099#endif /* CTK_CONF_WINDOWCLOSE */
1100 } else {
adamdunkels58917a82003-04-18 00:18:38 +00001101 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001102 w->window->owner);
1103 }
1104#if CTK_CONF_ICONS
1105 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +00001106 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001107 w->widget.icon.owner);
1108#endif /* CTK_CONF_ICONS */
1109 } else if(w->type == CTK_WIDGET_HYPERLINK) {
1110 dispatcher_emit(ctk_signal_hyperlink_activate, w,
1111 DISPATCHER_BROADCAST);
1112 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
1113 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
1114 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1115 len = strlen(w->widget.textentry.text);
1116 if(w->widget.textentry.xpos > len) {
1117 w->widget.textentry.xpos = len;
1118 }
1119 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1120 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +00001121 dispatcher_emit(ctk_signal_widget_activate, w,
1122 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001123 }
1124 add_redrawwidget(w);
1125 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +00001126 } else {
1127 dispatcher_emit(ctk_signal_widget_activate, w,
1128 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001129 }
1130 return REDRAW_NONE;
1131}
1132/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001133static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001134textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +00001135 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001136{
adamdunkelsaf610eb2003-08-05 13:50:51 +00001137 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001138 static unsigned char len, txpos, typos, tlen;
1139
1140 txpos = t->xpos;
1141 typos = t->ypos;
1142 tlen = t->len;
1143
1144 cptr = &t->text[txpos + typos * tlen];
1145
1146 switch(c) {
1147 case CH_CURS_LEFT:
1148 if(txpos > 0) {
1149 --txpos;
1150 }
1151 break;
1152
1153 case CH_CURS_RIGHT:
1154 if(txpos < tlen &&
1155 *cptr != 0) {
1156 ++txpos;
1157 }
1158 break;
1159
1160 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001161 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001162 break;
1163
1164 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001165 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001166 break;
1167
1168 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +00001169 /* t->state = CTK_TEXTENTRY_NORMAL;*/
1170 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +00001171 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001172 break;
1173
adamdunkels9795b2e2003-08-09 23:32:37 +00001174 case CTK_CONF_WIDGETDOWN_KEY:
1175 t->state = CTK_TEXTENTRY_NORMAL;
1176 switch_focus_widget(DOWN);
1177 break;
1178 case CTK_CONF_WIDGETUP_KEY:
1179 t->state = CTK_TEXTENTRY_NORMAL;
1180 switch_focus_widget(UP);
1181 break;
1182
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001183 default:
1184 len = tlen - txpos - 1;
1185 if(c == CH_DEL) {
1186 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +00001187 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001188 *(cptr + len - 1) = 0;
1189 --txpos;
1190 }
1191 } else {
1192 if(len > 0) {
1193 cptr2 = cptr + len - 1;
1194 while(cptr2 + 1 > cptr) {
1195 *(cptr2 + 1) = *cptr2;
1196 --cptr2;
1197 }
1198
1199 *cptr = c;
1200 ++txpos;
1201 }
1202 }
1203 break;
1204 }
1205
1206 t->xpos = txpos;
1207 t->ypos = typos;
1208}
1209/*-----------------------------------------------------------------------------------*/
1210#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +00001211static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001212activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001213{
1214 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001215
adamdunkelsb2486562003-04-11 20:22:03 +00001216 lastmenu = menus.open;
1217 if(menus.open == &desktopmenu) {
1218 for(w = windows; w != NULL; w = w->next) {
1219 if(w->title == desktopmenu.items[desktopmenu.active].title) {
1220 ctk_window_open(w);
1221 menus.open = NULL;
1222 return REDRAW_ALL;
1223 }
1224 }
1225 } else {
1226 dispatcher_emit(ctk_signal_menu_activate, menus.open,
1227 DISPATCHER_BROADCAST);
1228 }
1229 menus.open = NULL;
1230 return REDRAW_MENUPART;
1231}
1232/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +00001233static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +00001234menus_input(ctk_arch_key_t c)
1235{
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001236
1237 if(menus.open->nitems > maxnitems) {
1238 maxnitems = menus.open->nitems;
1239 }
1240
1241
1242 switch(c) {
1243 case CH_CURS_RIGHT:
1244 switch_open_menu(1);
1245
1246 return REDRAW_MENUPART;
1247
1248 case CH_CURS_DOWN:
1249 switch_menu_item(1);
1250 return REDRAW_MENUS;
1251
1252 case CH_CURS_LEFT:
1253 switch_open_menu(0);
1254 return REDRAW_MENUPART;
1255
1256 case CH_CURS_UP:
1257 switch_menu_item(0);
1258 return REDRAW_MENUS;
1259
1260 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001261 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001262
adamdunkels88ed9c42003-03-28 12:10:09 +00001263 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001264 lastmenu = menus.open;
1265 menus.open = NULL;
1266 return REDRAW_MENUPART;
1267 }
adamdunkelsb2486562003-04-11 20:22:03 +00001268
1269 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001270}
1271#endif /* CTK_CONF_MENUS */
1272/*-----------------------------------------------------------------------------------*/
1273static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001274timer(void)
1275{
1276 if(mode == CTK_MODE_NORMAL) {
1277 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001278 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001279#if CTK_CONF_SCREENSAVER
1280 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1281 DISPATCHER_BROADCAST);
1282#ifdef CTK_SCREENSAVER_INIT
1283 CTK_SCREENSAVER_INIT();
1284#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001285
adamdunkelscf90b0d2003-08-09 13:34:16 +00001286#endif /* CTK_CONF_SCREENSAVER */
1287 screensaver_timer = 0;
1288 }
1289 }
1290}
1291/*-----------------------------------------------------------------------------------*/
1292static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001293unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1294{
1295 if(w != NULL) {
1296 redraw |= REDRAW_WIDGETS;
1297 add_redrawwidget(w);
1298 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1299 ((struct ctk_textentry *)w)->state =
1300 CTK_TEXTENTRY_NORMAL;
1301 }
1302 w->window->focused = NULL;
1303 }
1304}
1305/*-----------------------------------------------------------------------------------*/
1306static void
adamdunkelsc4902862003-04-09 00:30:45 +00001307ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001308{
1309 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001310 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001311 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001312 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001313 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001314#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001315 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1316 mouse_clicked;
1317 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001318 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001319
adamdunkels19a787c2003-04-09 09:22:24 +00001320#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001321
1322
1323 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001324
adamdunkels9795b2e2003-08-09 23:32:37 +00001325 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001326 timer();
1327 start = current;
1328 }
1329
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001330#if CTK_CONF_MENUS
1331 if(menus.open != NULL) {
1332 maxnitems = menus.open->nitems;
1333 } else {
1334 maxnitems = 0;
1335 }
1336#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001337
1338#if CTK_CONF_MOUSE_SUPPORT
1339 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1340
1341 /* See if there is any change in the buttons. */
1342 if(ctk_mouse_button() != mouse_button) {
1343 mouse_button = ctk_mouse_button();
1344 mouse_button_changed = 1;
1345 if(mouse_button == 0) {
1346 mouse_clicked = 1;
1347 }
1348 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001349
adamdunkelsb2486562003-04-11 20:22:03 +00001350 /* Check if the mouse pointer has moved. */
1351 if(ctk_mouse_x() != mouse_x ||
1352 ctk_mouse_y() != mouse_y) {
1353 mouse_x = ctk_mouse_x();
1354 mouse_y = ctk_mouse_y();
1355 mouse_moved = 1;
1356 }
1357
1358 mxc = ctk_mouse_xtoc(mouse_x);
1359 myc = ctk_mouse_ytoc(mouse_y);
1360#endif /* CTK_CONF_MOUSE_SUPPORT */
1361
1362
adamdunkels66109622003-04-24 17:17:10 +00001363#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001365 if(ctk_arch_keyavail()
1366#if CTK_CONF_MOUSE_SUPPORT
1367 || mouse_moved || mouse_button_changed
1368#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001369 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001370 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1371 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001372 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001373 }
adamdunkels66109622003-04-24 17:17:10 +00001374 } else
1375#endif /* CTK_CONF_SCREENSAVER */
1376 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001377#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001378 /* If there is any change in the mouse conditions, find out in
1379 which window the mouse pointer currently is in order to send
1380 the correct signals, or bring a window to focus. */
1381 if(mouse_moved || mouse_button_changed) {
1382 ctk_mouse_show();
1383 screensaver_timer = 0;
1384
1385 if(myc == 0) {
1386 /* Here we should do whatever needs to be done when the mouse
1387 moves around and clicks in the menubar. */
1388 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001389 static unsigned char titlelen;
1390
adamdunkelsb2486562003-04-11 20:22:03 +00001391 /* Find out which menu that the mouse pointer is in. Start
1392 with the ->next menu after the desktop menu. We assume
1393 that the menus start one character from the left screen
1394 side and that the desktop menu is farthest to the
1395 right. */
1396 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001397 for(menu = menus.menus->next;
1398 menu != NULL; menu = menu->next) {
1399 titlelen = menu->titlelen;
1400 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001401 break;
adamdunkelse0683312003-04-09 09:02:52 +00001402 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001403 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001404 }
adamdunkelsb2486562003-04-11 20:22:03 +00001405
1406 /* Also check desktop menu. */
1407 if(mxc >= width - 7 &&
1408 mxc <= width - 1) {
1409 menu = &desktopmenu;
1410 }
1411
1412 menus.open = menu;
1413 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001414 }
adamdunkelse0683312003-04-09 09:02:52 +00001415 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001416 --myc;
1417
1418 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001419 static unsigned char nitems;
1420
adamdunkelsb2486562003-04-11 20:22:03 +00001421 /* Do whatever needs to be done when a menu is open. */
1422
adamdunkelscf90b0d2003-08-09 13:34:16 +00001423 /* First check if the mouse pointer is in the currently open
1424 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001425 if(menus.open == &desktopmenu) {
1426 menux = width - CTK_CONF_MENUWIDTH;
1427 } else {
1428 menux = 1;
1429 for(menu = menus.menus->next; menu != menus.open;
1430 menu = menu->next) {
1431 menux += menu->titlelen;
1432 }
1433 }
1434
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001435 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001436 /* Find out which of the menu items the mouse is pointing
1437 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001438 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1439 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001440 menus.open->active = myc;
1441 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001442 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001443 }
adamdunkelsb2486562003-04-11 20:22:03 +00001444 }
1445
1446 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001447 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001448 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001449 redraw |= activate_menu();
1450 } else {
1451 lastmenu = menus.open;
1452 menus.open = NULL;
1453 redraw |= REDRAW_MENUPART;
1454 }
1455 } else {
1456 redraw |= REDRAW_MENUS;
1457 }
1458 } else {
1459
adamdunkels965e2922003-06-30 20:44:57 +00001460 /* Walk through the windows from top to bottom to see in
1461 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001462 if(dialog != NULL) {
1463 window = dialog;
1464 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001465 for(window = windows; window != NULL;
1466 window = window->next) {
1467
adamdunkelsb2486562003-04-11 20:22:03 +00001468 /* Check if the mouse is within the window. */
1469 if(mxc >= window->x &&
1470 mxc <= window->x + window->w &&
1471 myc >= window->y &&
1472 myc <= window->y + window->h) {
1473 break;
1474 }
1475 }
1476 }
1477
1478
1479 /* If we didn't find any window, and there are no windows
1480 open, the mouse pointer will definately be within the
1481 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001482 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001483 window = &desktop_window;
1484 }
1485
adamdunkels965e2922003-06-30 20:44:57 +00001486 /* If the mouse pointer moves around outside of the
1487 currently focused window (or dialog), we should not have
1488 any focused widgets in the focused window so we make sure
1489 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001490 if(windows != NULL &&
1491 window != windows &&
1492 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001493 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001494 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001495 redraw |= REDRAW_WIDGETS;*/
1496 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001497 }
1498
1499 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001500 /* If the mouse was clicked outside of the current window,
1501 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001502 if(dialog == NULL &&
1503 window != &desktop_window &&
1504 window != windows &&
1505 mouse_clicked) {
1506 /* Bring window to front. */
1507 ctk_window_open(window);
1508 redraw |= REDRAW_ALL;
1509 } else {
1510
adamdunkels965e2922003-06-30 20:44:57 +00001511 /* Find out which widget currently is under the mouse
1512 pointer and give it focus, unless it already has
1513 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001514 mxc = mxc - window->x - 1;
1515 myc = myc - window->y - 1;
1516
adamdunkels965e2922003-06-30 20:44:57 +00001517 /* See if the mouse pointer is on a widget. If so, it
1518 should be selected and, if the button is clicked,
1519 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001520 for(widget = window->active; widget != NULL;
1521 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001522
adamdunkelsb2486562003-04-11 20:22:03 +00001523 if(mxc >= widget->x &&
1524 mxc <= widget->x + widget->w &&
1525 (myc == widget->y ||
1526 ((widget->type == CTK_WIDGET_BITMAP ||
1527 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1528 widget->type == CTK_WIDGET_ICON) &&
1529 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001530 myc <= widget->y +
1531 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001532 break;
1533 }
1534 }
1535
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001536
1537 /* if the mouse is moved in the focused window, we emit
1538 a ctk_signal_pointer_move signal to the owner of the
1539 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001540 if(mouse_moved &&
1541 (window != &desktop_window ||
1542 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001543
adamdunkelsb2486562003-04-11 20:22:03 +00001544 dispatcher_emit(ctk_signal_pointer_move, NULL,
1545 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001546
1547 /* If there was a focused widget that is not below the
1548 mouse pointer, we remove focus from the widget and
1549 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001550 if(window->focused != NULL &&
1551 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001552 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001553 if(CTK_WIDGET_TYPE(window->focused) ==
1554 CTK_WIDGET_TEXTENTRY) {
1555 ((struct ctk_textentry *)(window->focused))->state =
1556 CTK_TEXTENTRY_NORMAL;
1557 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001558 window->focused = NULL;*/
1559 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001560 }
1561 redraw |= REDRAW_WIDGETS;
1562 if(widget != NULL) {
1563 select_widget(widget);
1564 }
1565 }
1566
1567 if(mouse_button_changed) {
1568 dispatcher_emit(ctk_signal_pointer_button,
1569 (ek_data_t)mouse_button,
1570 window->owner);
1571 if(mouse_clicked && widget != NULL) {
1572 select_widget(widget);
1573 redraw |= activate(widget);
1574 }
1575 }
1576 }
1577 }
1578 }
adamdunkelsc4902862003-04-09 00:30:45 +00001579 }
1580 }
adamdunkels19a787c2003-04-09 09:22:24 +00001581#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001582
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001583 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001584
1585 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001586
1587 screensaver_timer = 0;
1588
adamdunkelsb2486562003-04-11 20:22:03 +00001589 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001590
1591 if(dialog != NULL) {
1592 window = dialog;
1593 } else if(windows != NULL) {
1594 window = windows;
1595 } else {
1596 window = &desktop_window;
1597 }
1598 widget = window->focused;
1599
1600
1601 if(widget != NULL &&
1602 widget->type == CTK_WIDGET_TEXTENTRY &&
1603 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1604 textentry_input(c, (struct ctk_textentry *)widget);
1605 add_redrawwidget(widget);
1606#if CTK_CONF_MENUS
1607 } else if(menus.open != NULL) {
1608 redraw |= menus_input(c);
1609#endif /* CTK_CONF_MENUS */
1610 } else {
1611 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001612 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001613 switch_focus_widget(DOWN);
1614 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001615 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001616 switch_focus_widget(UP);
1617 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001618#if CTK_CONF_MENUS
1619 case CTK_CONF_MENU_KEY:
1620 if(dialog == NULL) {
1621 if(lastmenu == NULL) {
1622 menus.open = menus.menus;
1623 } else {
1624 menus.open = lastmenu;
1625 }
1626 menus.open->active = 0;
1627 redraw |= REDRAW_MENUS;
1628 }
1629 break;
1630#endif /* CTK_CONF_MENUS */
1631 case CTK_CONF_WINDOWSWITCH_KEY:
1632 if(windows != NULL) {
1633 for(window = windows; window->next != NULL;
1634 window = window->next);
1635 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001636 }
1637 break;
1638 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001639 if(c == CH_ENTER &&
1640 widget != NULL) {
1641 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001642 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001643 if(widget != NULL &&
1644 widget->type == CTK_WIDGET_TEXTENTRY) {
1645 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1646 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001647 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001648 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001649 /* window->focused = NULL;*/
1650 unfocus_widget(window->focused);
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001651 dispatcher_fastemit(ctk_signal_keypress, (void *)c,
1652 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001653 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001654 }
1655 break;
1656 }
1657 }
1658
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001659#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001660 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001661 widgetptr = redraw_widgets;
1662 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001663 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001664 *widgetptr = NULL;
1665 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001666 }
1667 redraw &= ~REDRAW_WIDGETS;
1668 redraw_widgetptr = 0;
1669 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001670#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001671 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001672#if CTK_CONF_WINDOWMOVE
1673 } else if(mode == CTK_MODE_WINDOWMOVE) {
1674
1675 redraw = 0;
1676
1677 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001678
1679#if CTK_CONF_MOUSE_SUPPORT
1680
1681 /* If the mouse has moved, we move the window as well. */
1682 if(mouse_moved) {
1683
1684 if(window->w + mxc + 2 >= width) {
1685 window->x = width - 2 - window->w;
1686 } else {
1687 window->x = mxc;
1688 }
1689
1690 if(window->h + myc + 2 >= height) {
1691 window->y = height - 2 - window->h;
1692 } else {
1693 window->y = myc;
1694 }
1695 if(window->y > 0) {
1696 --window->y;
1697 }
1698
1699 redraw = REDRAW_ALL;
1700 }
1701
1702 /* Check if the mouse has been clicked, and stop moving the window
1703 if so. */
1704 if(mouse_button_changed &&
1705 mouse_button == 0) {
1706 mode = CTK_MODE_NORMAL;
1707 redraw = REDRAW_ALL;
1708 }
1709#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001710
1711 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1712
1713 screensaver_timer = 0;
1714
1715 c = ctk_arch_getkey();
1716
1717 switch(c) {
1718 case CH_CURS_RIGHT:
1719 ++window->x;
1720 if(window->x + window->w + 1 >= width) {
1721 --window->x;
1722 }
1723 redraw = REDRAW_ALL;
1724 break;
1725 case CH_CURS_LEFT:
1726 if(window->x > 0) {
1727 --window->x;
1728 }
1729 redraw = REDRAW_ALL;
1730 break;
1731 case CH_CURS_DOWN:
1732 ++window->y;
1733 if(window->y + window->h + 2 >= height) {
1734 --window->y;
1735 }
1736 redraw = REDRAW_ALL;
1737 break;
1738 case CH_CURS_UP:
1739 if(window->y > 0) {
1740 --window->y;
1741 }
1742 redraw = REDRAW_ALL;
1743 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001744 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001745 mode = CTK_MODE_NORMAL;
1746 redraw = REDRAW_ALL;
1747 break;
1748 }
1749 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001750#endif /* CTK_CONF_WINDOWMOVE */
1751 }
adamdunkelsb2486562003-04-11 20:22:03 +00001752
1753 if(redraw & REDRAW_ALL) {
1754 do_redraw_all(1, height);
1755#if CTK_CONF_MENUS
1756 } else if(redraw & REDRAW_MENUPART) {
1757 do_redraw_all(1, maxnitems + 1);
1758 } else if(redraw & REDRAW_MENUS) {
1759 ctk_draw_menus(&menus);
1760#endif /* CTK_CONF_MENUS */
1761 } else if(redraw & REDRAW_FOCUS) {
1762 if(dialog != NULL) {
1763 ctk_window_redraw(dialog);
1764 } else if(windows != NULL) {
1765 ctk_window_redraw(windows);
1766 } else {
1767 ctk_window_redraw(&desktop_window);
1768 }
1769 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001770 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001771 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001772 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001773 *widgetptr = NULL;
1774 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001775 }
1776 }
1777 redraw = 0;
1778 redraw_widgetptr = 0;
1779
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001780}
1781/*-----------------------------------------------------------------------------------*/