blob: 61cd3e66bcd9644c28f8962d543c43cbf85ffd99 [file] [log] [blame]
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001/*
2 * Copyright (c) 2002, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * 3. All advertising materials mentioning features or use of this
15 * software must display the following acknowledgement:
16 * This product includes software developed by Adam Dunkels.
17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * This file is part of the "ctk" console GUI toolkit for cc65
34 *
adamdunkels46623032003-08-12 21:12:59 +000035 * $Id: ctk.c,v 1.26 2003/08/12 21:12:59 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000036 *
37 */
38
adamdunkelsd07a5422003-04-05 12:22:35 +000039#include "cc.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000040#include "ek.h"
41#include "dispatcher.h"
42#include "ctk.h"
43#include "ctk-draw.h"
44#include "ctk-conf.h"
adamdunkelsc4902862003-04-09 00:30:45 +000045#include "ctk-mouse.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000046
adamdunkels591724c2003-08-01 00:07:19 +000047#include <string.h>
48
adamdunkelsca9ddcb2003-03-19 14:13:31 +000049static unsigned char height, width;
50
51static unsigned char mode;
52
53static struct ctk_window desktop_window;
54static struct ctk_window *windows;
55static struct ctk_window *dialog;
56
57#if CTK_CONF_MENUS
58static struct ctk_menus menus;
59static struct ctk_menu *lastmenu;
60static struct ctk_menu desktopmenu;
61#endif /* CTK_CONF_MENUS */
62
63#ifndef NULL
64#define NULL (void *)0
65#endif /* NULL */
66
67
68#define REDRAW_NONE 0
69#define REDRAW_ALL 1
70#define REDRAW_FOCUS 2
71#define REDRAW_WIDGETS 4
72#define REDRAW_MENUS 8
73#define REDRAW_MENUPART 16
74
75#define MAX_REDRAWWIDGETS 4
76static unsigned char redraw;
77static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
78static unsigned char redraw_widgetptr;
79static unsigned char maxnitems;
80
81static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000082#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000083#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000084#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000085#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000086#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000087
adamdunkelsc4902862003-04-09 00:30:45 +000088static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000089static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +000090 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091static ek_id_t ctkid;
92
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093ek_signal_t ctk_signal_keypress,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094 ctk_signal_button_activate,
adamdunkels58917a82003-04-18 00:18:38 +000095 ctk_signal_widget_activate,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096 ctk_signal_button_hover,
adamdunkels58917a82003-04-18 00:18:38 +000097 ctk_signal_widget_select,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098 ctk_signal_hyperlink_activate,
99 ctk_signal_hyperlink_hover,
100 ctk_signal_menu_activate,
adamdunkelsc4902862003-04-09 00:30:45 +0000101 ctk_signal_window_close,
102 ctk_signal_pointer_move,
adamdunkelsb2486562003-04-11 20:22:03 +0000103 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000104
adamdunkels66109622003-04-24 17:17:10 +0000105#if CTK_CONF_SCREENSAVER
adamdunkels9795b2e2003-08-09 23:32:37 +0000106ek_signal_t ctk_signal_screensaver_stop,
107 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000108#endif /* CTK_CONF_SCREENSAVER */
109
110
adamdunkels19a787c2003-04-09 09:22:24 +0000111#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000112unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000113#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000114
adamdunkels9795b2e2003-08-09 23:32:37 +0000115static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000116unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels9795b2e2003-08-09 23:32:37 +0000117static ek_clock_t start, current;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000118
119#if CTK_CONF_MENUS
120/*-----------------------------------------------------------------------------------*/
121/* make_desktopmenu(void)
122 *
123 * Creates the leftmost menu, "Desktop". Since the desktop menu
124 * contains the list of all open windows, this function will be called
125 * whenever a window is opened or closed.
126 */
127static void
128make_desktopmenu(void)
129{
130 struct ctk_window *w;
131
132 desktopmenu.nitems = 0;
133
134 if(windows == NULL) {
135 ctk_menuitem_add(&desktopmenu, "(No windows)");
136 } else {
137 for(w = windows; w != NULL; w = w->next) {
138 ctk_menuitem_add(&desktopmenu, w->title);
139 }
140 }
141}
142#endif /* CTK_CONF_MENUS */
143/*-----------------------------------------------------------------------------------*/
144/* ctk_init(void)
145 *
146 * Initializes CTK. Must be called before any other CTK function.
147 */
148void
149ctk_init(void)
150{
151 ctkid = dispatcher_start(&p);
152
153 windows = NULL;
154 dialog = NULL;
155
156#if CTK_CONF_MENUS
157 ctk_menu_new(&desktopmenu, "Desktop");
158 make_desktopmenu();
159 menus.menus = menus.desktopmenu = &desktopmenu;
160#endif /* CTK_CONF_MENUS */
161
adamdunkelsb2486562003-04-11 20:22:03 +0000162#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000163 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000164 ctk_mouse_show();
165#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000166
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000167 ctk_draw_init();
168
169 height = ctk_draw_height();
170 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000171
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000172 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000173
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000174 ctk_signal_keypress = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000175
176 ctk_signal_button_activate =
177 ctk_signal_widget_activate = dispatcher_sigalloc();
178
179 ctk_signal_button_hover =
180 ctk_signal_hyperlink_hover =
181 ctk_signal_widget_select = dispatcher_sigalloc();
182
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000183 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000184
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000185 ctk_signal_menu_activate = dispatcher_sigalloc();
186 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000187
188 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000189 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000190
191
192#if CTK_CONF_SCREENSAVER
193 ctk_signal_screensaver_start = dispatcher_sigalloc();
194 ctk_signal_screensaver_stop = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000195#endif /* CTK_CONF_SCREENSAVER */
196
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000197
198 mode = CTK_MODE_NORMAL;
199
200 iconx = ICONX_START;
201 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000202
203 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000204
205 start = ek_clock();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000206}
207/*-----------------------------------------------------------------------------------*/
208/* void ctk_mode_set()
209 */
210void
211ctk_mode_set(unsigned char m) {
212 mode = m;
213}
214/*-----------------------------------------------------------------------------------*/
215unsigned char
216ctk_mode_get(void) {
217 return mode;
218}
219/*-----------------------------------------------------------------------------------*/
220void
adamdunkelsd07a5422003-04-05 12:22:35 +0000221ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000222 ek_id_t id)
223{
224#if CTK_CONF_ICONS
225 icon->x = iconx;
226 icon->y = icony;
227 icon->widget.icon.owner = id;
228
229 icony += ICONY_DELTA;
230 if(icony >= ICONY_MAX) {
231 icony = ICONY_START;
232 iconx += ICONX_DELTA;
233 }
234
235 ctk_widget_add(&desktop_window, icon);
236#endif /* CTK_CONF_ICONS */
237}
238/*-----------------------------------------------------------------------------------*/
239void
240ctk_dialog_open(struct ctk_window *d)
241{
242 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000243 redraw |= REDRAW_FOCUS;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000244}
245/*-----------------------------------------------------------------------------------*/
246void
247ctk_dialog_close(void)
248{
249 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000250 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000251}
252/*-----------------------------------------------------------------------------------*/
253void
adamdunkelsd07a5422003-04-05 12:22:35 +0000254ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255{
256 struct ctk_window *w2;
257
258 /* Check if already open. */
259 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
260 if(w2 == NULL) {
261 /* Not open, so we add it at the head of the list of open
262 windows. */
263 w->next = windows;
264 if(windows != NULL) {
265 windows->prev = w;
266 }
267 windows = w;
268 w->prev = NULL;
269 } else {
270 /* Window already open, so we move it to the front of the windows
271 list. */
272 if(w != windows) {
273 if(w->next != NULL) {
274 w->next->prev = w->prev;
275 }
276 if(w->prev != NULL) {
277 w->prev->next = w->next;
278 }
279 w->next = windows;
280 windows->prev = w;
281 windows = w;
282 w->prev = NULL;
283 }
284 }
285
286#if CTK_CONF_MENUS
287 /* Recreate the Desktop menu's window entries.*/
288 make_desktopmenu();
289#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000290
291 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000292}
293/*-----------------------------------------------------------------------------------*/
294void
295ctk_window_close(struct ctk_window *w)
296{
297 struct ctk_window *w2;
298
299 if(w == NULL) {
300 return;
301 }
302
303 /* Check if the window to be closed is the first window on the
304 list. */
305 if(w == windows) {
306 windows = w->next;
307 if(windows != NULL) {
308 windows->prev = NULL;
309 }
310 w->next = w->prev = NULL;
311 } else {
312 /* Otherwise we step through the list until we find the window
313 before the one to be closed. We then redirect its ->next
314 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000315 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
316
317 if(w2 == NULL) {
318 /* The window wasn't open, so there is nothing more for us to
319 do. */
320 return;
321 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322
323 if(w->next != NULL) {
324 w->next->prev = w->prev;
325 }
326 w2->next = w->next;
327
328 w->next = w->prev = NULL;
329 }
330
331#if CTK_CONF_MENUS
332 /* Recreate the Desktop menu's window entries.*/
333 make_desktopmenu();
334#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000335 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000336}
337/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000338static void
339make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000340{
341#if CTK_CONF_WINDOWMOVE
342 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
343#else
344 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
345#endif /* CTK_CONF_WINDOWMOVE */
346 CTK_WIDGET_ADD(window, &window->titlebutton);
347
348
349#if CTK_CONF_WINDOWCLOSE
350 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
351#else
352 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
353#endif /* CTK_CONF_WINDOWCLOSE */
354 CTK_WIDGET_ADD(window, &window->closebutton);
355}
356/*-----------------------------------------------------------------------------------*/
357void
358ctk_window_clear(struct ctk_window *window)
359{
360 window->active = window->inactive = window->focused = NULL;
361
362 make_windowbuttons(window);
363}
364/*-----------------------------------------------------------------------------------*/
365void
366ctk_menu_add(struct ctk_menu *menu)
367{
368#if CTK_CONF_MENUS
369 struct ctk_menu *m;
370
371 if(lastmenu == NULL) {
372 lastmenu = menu;
373 }
374
375 for(m = menus.menus; m->next != NULL; m = m->next) {
376 if(m == menu) {
377 return;
378 }
379 }
380 m->next = menu;
381 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000382
383 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000384#endif /* CTK_CONF_MENUS */
385}
386/*-----------------------------------------------------------------------------------*/
387void
388ctk_menu_remove(struct ctk_menu *menu)
389{
390#if CTK_CONF_MENUS
391 struct ctk_menu *m;
392
393 for(m = menus.menus; m->next != NULL; m = m->next) {
394 if(m->next == menu) {
395 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000396 if(menu == lastmenu) {
397 lastmenu = NULL;
398 }
399 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000400 return;
401 }
402 }
403#endif /* CTK_CONF_MENUS */
404}
405/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000406static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000407do_redraw_all(unsigned char clipy1, unsigned char clipy2)
408{
409 struct ctk_window *w;
410 struct ctk_widget *widget;
411
412 if(mode != CTK_MODE_NORMAL &&
413 mode != CTK_MODE_WINDOWMOVE) {
414 return;
415 }
416
417 ctk_draw_clear(clipy1, clipy2);
418
419 /* Draw widgets in root window */
420 for(widget = desktop_window.active;
421 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000422 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000423 }
424
425 /* Draw windows */
426 if(windows != NULL) {
427 /* Find the last window.*/
428 for(w = windows; w->next != NULL; w = w->next);
429
430 /* Draw the windows from back to front. */
431 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000432 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000433 ctk_draw_window(w, 0, clipy1, clipy2);
434 }
435 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000436 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000437 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
438 }
439
440 /* Draw dialog (if any) */
441 if(dialog != NULL) {
442 ctk_draw_dialog(dialog);
443 }
444
445#if CTK_CONF_MENUS
446 ctk_draw_menus(&menus);
447#endif /* CTK_CONF_MENUS */
448}
449/*-----------------------------------------------------------------------------------*/
450void
adamdunkels965e2922003-06-30 20:44:57 +0000451ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000452{
453 if(DISPATCHER_CURRENT() == ctkid) {
454 if(mode == CTK_MODE_NORMAL ||
455 mode == CTK_MODE_WINDOWMOVE) {
456 do_redraw_all(1, height);
457 }
458 } else {
459 redraw |= REDRAW_ALL;
460 }
461}
462/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000463void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000464ctk_window_redraw(struct ctk_window *w)
465{
466 /* Only redraw the window if it is a dialog or if it is the foremost
467 window. */
468 if(mode != CTK_MODE_NORMAL) {
469 return;
470 }
471
472 if(w == dialog) {
473 ctk_draw_dialog(w);
474 } else if(dialog == NULL &&
475#if CTK_CONF_MENUS
476 menus.open == NULL &&
477#endif /* CTK_CONF_MENUS */
478 windows == w) {
479 ctk_draw_window(w, CTK_FOCUS_WINDOW,
480 0, height);
481 }
482}
483/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000484static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000485window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000486 unsigned char w, unsigned char h,
487 char *title)
488{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000489
490 if(w >= width - 2) {
491 window->x = 0;
492 } else {
493 window->x = (width - w - 2) / 2;
494 }
495 if(h >= height - 3) {
496 window->y = 0;
497 } else {
498 window->y = (height - h - 1) / 2;
499 }
500
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000501 window->w = w;
502 window->h = h;
503 window->title = title;
504 if(title != NULL) {
505 window->titlelen = strlen(title);
506 } else {
507 window->titlelen = 0;
508 }
509 window->next = window->prev = NULL;
510 window->owner = DISPATCHER_CURRENT();
511 window->active = window->inactive = window->focused = NULL;
512}
513/*-----------------------------------------------------------------------------------*/
514void
515ctk_window_new(struct ctk_window *window,
516 unsigned char w, unsigned char h,
517 char *title)
518{
519 window_new(window, w, h, title);
520
521 make_windowbuttons(window);
522}
523/*-----------------------------------------------------------------------------------*/
524void
adamdunkelsd07a5422003-04-05 12:22:35 +0000525ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526 unsigned char w, unsigned char h)
527{
528 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529}
adamdunkels3af580f2003-08-11 22:27:13 +0000530/*-----------------------------------------------------------------------------------*/
531void
adamdunkelsd07a5422003-04-05 12:22:35 +0000532ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000533 char *title)
534{
535#if CTK_CONF_MENUS
536 menu->next = NULL;
537 menu->title = title;
538 menu->titlelen = strlen(title);
539 menu->active = 0;
540 menu->nitems = 0;
541#endif /* CTK_CONF_MENUS */
542}
543/*-----------------------------------------------------------------------------------*/
544unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000545ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000546 char *name)
547{
548#if CTK_CONF_MENUS
549 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
550 return 0;
551 }
552 menu->items[menu->nitems].title = name;
553 menu->items[menu->nitems].titlelen = strlen(name);
554 return menu->nitems++;
555#else
556 return 0;
557#endif /* CTK_CONF_MENUS */
558}
559/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000560static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000561add_redrawwidget(struct ctk_widget *w)
562{
563 static unsigned char i;
564
565 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
566 redraw |= REDRAW_FOCUS;
567 } else {
568 redraw |= REDRAW_WIDGETS;
569 /* Check if it is in the queue already. If so, we don't add it
570 again. */
571 for(i = 0; i < redraw_widgetptr; ++i) {
572 if(redraw_widgets[i] == w) {
573 return;
574 }
575 }
576 redraw_widgets[redraw_widgetptr++] = w;
577 }
578}
579/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000580void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000581ctk_widget_redraw(struct ctk_widget *widget)
582{
583 struct ctk_window *window;
584
adamdunkels9f667f22003-04-16 18:29:19 +0000585 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000586 return;
587 }
588
589 /* If this function isn't called by CTK itself, we only queue the
590 redraw request. */
591 if(DISPATCHER_CURRENT() != ctkid) {
592 redraw |= REDRAW_WIDGETS;
593 add_redrawwidget(widget);
594 } else {
595
596 /* Only redraw widgets that are in the foremost window. If we
597 would allow redrawing widgets in non-focused windows, we would
598 have to redraw all the windows that cover the non-focused
599 window as well, which would lead to flickering.
600
601 Also, we avoid drawing any widgets when the menus are active.
602 */
603
604#if CTK_CONF_MENUS
605 if(menus.open == NULL)
606#endif /* CTK_CONF_MENUS */
607 {
608 window = widget->window;
609 if(window == dialog) {
610 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels47efbc42003-08-07 00:03:26 +0000611 } else if(dialog == NULL &&
adamdunkels9795b2e2003-08-09 23:32:37 +0000612 (window == windows ||
613 window == &desktop_window)) {
adamdunkels66109622003-04-24 17:17:10 +0000614 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000615 }
616 }
617 }
618}
619/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000620void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000621ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
622 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000623{
624 if(widget->type == CTK_WIDGET_LABEL ||
625 widget->type == CTK_WIDGET_SEPARATOR) {
626 widget->next = window->inactive;
627 window->inactive = widget;
628 widget->window = window;
629 } else {
630 widget->next = window->active;
631 window->active = widget;
632 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000633 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000634 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000635 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000636 }
637}
638/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000639unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000640ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000641{
642 return ctk_draw_width();
643}
644/*-----------------------------------------------------------------------------------*/
645unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000646ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000647{
648 return ctk_draw_height();
649}
650/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000651static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000652select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000653{
654 struct ctk_window *window;
655
656 window = focus->window;
657
658 if(focus != window->focused) {
659 window->focused = focus;
660 /* The operation changed the focus, so we emit a "hover" signal
661 for those widgets that support it. */
662
663 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
664 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
665 window->owner);
666 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
667 dispatcher_emit(ctk_signal_button_hover, window->focused,
668 window->owner);
669 }
670
671 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000672
673 dispatcher_emit(ctk_signal_widget_select, focus,
674 focus->window->owner);
675
adamdunkelse0683312003-04-09 09:02:52 +0000676 }
677
678}
679/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000680#define UP 0
681#define DOWN 1
682#define LEFT 2
683#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000684static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000685switch_focus_widget(unsigned char direction)
686{
687 register struct ctk_window *window;
688 register struct ctk_widget *focus;
689 struct ctk_widget *widget;
690
691
692 if(dialog != NULL) {
693 window = dialog;
694 } else {
695 window = windows;
696 }
697
698 /* If there are no windows open, we move focus around between the
699 icons on the root window instead. */
700 if(window == NULL) {
701 window = &desktop_window;
702 }
703
704 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000705 if(focus == NULL) {
706 focus = window->active;
707 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000708 add_redrawwidget(focus);
709
710 if((direction & 1) == 0) {
711 /* Move focus "up" */
712 focus = focus->next;
713 } else {
714 /* Move focus "down" */
715 for(widget = window->active;
716 widget != NULL; widget = widget->next) {
717 if(widget->next == focus) {
718 break;
719 }
720 }
721 focus = widget;
722 if(focus == NULL) {
723 if(window->active != NULL) {
724 for(focus = window->active;
725 focus->next != NULL; focus = focus->next);
726 }
727 }
728 }
729 if(focus == NULL) {
730 focus = window->active;
731 }
adamdunkelse0683312003-04-09 09:02:52 +0000732
adamdunkelsb2486562003-04-11 20:22:03 +0000733 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000734}
735/*-----------------------------------------------------------------------------------*/
736#if CTK_CONF_MENUS
737static void
738switch_open_menu(unsigned char rightleft)
739{
740 struct ctk_menu *menu;
741
742 if(rightleft == 0) {
743 /* Move right */
744 for(menu = menus.menus; menu != NULL; menu = menu->next) {
745 if(menu->next == menus.open) {
746 break;
747 }
748 }
749 lastmenu = menus.open;
750 menus.open = menu;
751 if(menus.open == NULL) {
752 for(menu = menus.menus;
753 menu->next != NULL; menu = menu->next);
754 menus.open = menu;
755 }
756 } else {
757 /* Move to left */
758 lastmenu = menus.open;
759 menus.open = menus.open->next;
760 if(menus.open == NULL) {
761 menus.open = menus.menus;
762 }
763 }
764
adamdunkels66109622003-04-24 17:17:10 +0000765 menus.open->active = 0;
766
767 /* if(menus.open->nitems > maxnitems) {
768 maxnitems = menus.open->nitems;
769 }*/
770
adamdunkels965e2922003-06-30 20:44:57 +0000771 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772}
773/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000774static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000775switch_menu_item(unsigned char updown)
776{
777 register struct ctk_menu *m;
778
779 m = menus.open;
780
781 if(updown == 0) {
782 /* Move up */
783 if(m->active == 0) {
784 m->active = m->nitems - 1;
785 } else {
786 --m->active;
787 if(m->items[m->active].title[0] == '-') {
788 --m->active;
789 }
790 }
791 } else {
792 /* Move down */
793 if(m->active >= m->nitems - 1) {
794 m->active = 0;
795 } else {
796 ++m->active;
797 if(m->items[m->active].title[0] == '-') {
798 ++m->active;
799 }
800 }
801 }
802
803}
804#endif /* CTK_CONF_MENUS */
805/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000806static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000807activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808{
809 static unsigned char len;
810
811 if(w->type == CTK_WIDGET_BUTTON) {
812 if(w == (struct ctk_widget *)&windows->closebutton) {
813#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000814 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000815 ctk_window_close(windows);
816 return REDRAW_ALL;
817#endif /* CTK_CONF_WINDOWCLOSE */
818 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
819#if CTK_CONF_WINDOWCLOSE
820 mode = CTK_MODE_WINDOWMOVE;
821#endif /* CTK_CONF_WINDOWCLOSE */
822 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000823 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000824 w->window->owner);
825 }
826#if CTK_CONF_ICONS
827 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000828 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 w->widget.icon.owner);
830#endif /* CTK_CONF_ICONS */
831 } else if(w->type == CTK_WIDGET_HYPERLINK) {
832 dispatcher_emit(ctk_signal_hyperlink_activate, w,
833 DISPATCHER_BROADCAST);
834 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
835 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
836 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
837 len = strlen(w->widget.textentry.text);
838 if(w->widget.textentry.xpos > len) {
839 w->widget.textentry.xpos = len;
840 }
841 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
842 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
843 }
844 add_redrawwidget(w);
845 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000846 } else {
847 dispatcher_emit(ctk_signal_widget_activate, w,
848 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849 }
850 return REDRAW_NONE;
851}
852/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000853static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000855 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000857 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858 static unsigned char len, txpos, typos, tlen;
859
860 txpos = t->xpos;
861 typos = t->ypos;
862 tlen = t->len;
863
864 cptr = &t->text[txpos + typos * tlen];
865
866 switch(c) {
867 case CH_CURS_LEFT:
868 if(txpos > 0) {
869 --txpos;
870 }
871 break;
872
873 case CH_CURS_RIGHT:
874 if(txpos < tlen &&
875 *cptr != 0) {
876 ++txpos;
877 }
878 break;
879
880 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000881 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882 break;
883
884 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000885 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000886 break;
887
888 case CH_ENTER:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000889 t->state = CTK_TEXTENTRY_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000890 break;
891
adamdunkels9795b2e2003-08-09 23:32:37 +0000892 case CTK_CONF_WIDGETDOWN_KEY:
893 t->state = CTK_TEXTENTRY_NORMAL;
894 switch_focus_widget(DOWN);
895 break;
896 case CTK_CONF_WIDGETUP_KEY:
897 t->state = CTK_TEXTENTRY_NORMAL;
898 switch_focus_widget(UP);
899 break;
900
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000901 default:
902 len = tlen - txpos - 1;
903 if(c == CH_DEL) {
904 if(txpos > 0 && len > 0) {
905 strncpy(cptr - 1, cptr,
906 len);
907 *(cptr + len - 1) = 0;
908 --txpos;
909 }
910 } else {
911 if(len > 0) {
912 cptr2 = cptr + len - 1;
913 while(cptr2 + 1 > cptr) {
914 *(cptr2 + 1) = *cptr2;
915 --cptr2;
916 }
917
918 *cptr = c;
919 ++txpos;
920 }
921 }
922 break;
923 }
924
925 t->xpos = txpos;
926 t->ypos = typos;
927}
928/*-----------------------------------------------------------------------------------*/
929#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000930static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000931activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000932{
933 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000934
935 lastmenu = menus.open;
936 if(menus.open == &desktopmenu) {
937 for(w = windows; w != NULL; w = w->next) {
938 if(w->title == desktopmenu.items[desktopmenu.active].title) {
939 ctk_window_open(w);
940 menus.open = NULL;
941 return REDRAW_ALL;
942 }
943 }
944 } else {
945 dispatcher_emit(ctk_signal_menu_activate, menus.open,
946 DISPATCHER_BROADCAST);
947 }
948 menus.open = NULL;
949 return REDRAW_MENUPART;
950}
951/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000952static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000953menus_input(ctk_arch_key_t c)
954{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000955
956 if(menus.open->nitems > maxnitems) {
957 maxnitems = menus.open->nitems;
958 }
959
960
961 switch(c) {
962 case CH_CURS_RIGHT:
963 switch_open_menu(1);
964
965 return REDRAW_MENUPART;
966
967 case CH_CURS_DOWN:
968 switch_menu_item(1);
969 return REDRAW_MENUS;
970
971 case CH_CURS_LEFT:
972 switch_open_menu(0);
973 return REDRAW_MENUPART;
974
975 case CH_CURS_UP:
976 switch_menu_item(0);
977 return REDRAW_MENUS;
978
979 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000980 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000981
adamdunkels88ed9c42003-03-28 12:10:09 +0000982 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000983 lastmenu = menus.open;
984 menus.open = NULL;
985 return REDRAW_MENUPART;
986 }
adamdunkelsb2486562003-04-11 20:22:03 +0000987
988 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000989}
990#endif /* CTK_CONF_MENUS */
991/*-----------------------------------------------------------------------------------*/
992static void
adamdunkelscf90b0d2003-08-09 13:34:16 +0000993timer(void)
994{
995 if(mode == CTK_MODE_NORMAL) {
996 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +0000997 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +0000998#if CTK_CONF_SCREENSAVER
999 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1000 DISPATCHER_BROADCAST);
1001#ifdef CTK_SCREENSAVER_INIT
1002 CTK_SCREENSAVER_INIT();
1003#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001004
adamdunkelscf90b0d2003-08-09 13:34:16 +00001005#endif /* CTK_CONF_SCREENSAVER */
1006 screensaver_timer = 0;
1007 }
1008 }
1009}
1010/*-----------------------------------------------------------------------------------*/
1011static void
adamdunkelsc4902862003-04-09 00:30:45 +00001012ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001013{
1014 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001015 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001016 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001017 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001018 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001019#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001020 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1021 mouse_clicked;
1022 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001023 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001024
adamdunkels19a787c2003-04-09 09:22:24 +00001025#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001026
1027
1028 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001029
adamdunkels9795b2e2003-08-09 23:32:37 +00001030 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001031 timer();
1032 start = current;
1033 }
1034
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001035#if CTK_CONF_MENUS
1036 if(menus.open != NULL) {
1037 maxnitems = menus.open->nitems;
1038 } else {
1039 maxnitems = 0;
1040 }
1041#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001042
1043#if CTK_CONF_MOUSE_SUPPORT
1044 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1045
1046 /* See if there is any change in the buttons. */
1047 if(ctk_mouse_button() != mouse_button) {
1048 mouse_button = ctk_mouse_button();
1049 mouse_button_changed = 1;
1050 if(mouse_button == 0) {
1051 mouse_clicked = 1;
1052 }
1053 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001054
adamdunkelsb2486562003-04-11 20:22:03 +00001055 /* Check if the mouse pointer has moved. */
1056 if(ctk_mouse_x() != mouse_x ||
1057 ctk_mouse_y() != mouse_y) {
1058 mouse_x = ctk_mouse_x();
1059 mouse_y = ctk_mouse_y();
1060 mouse_moved = 1;
1061 }
1062
1063 mxc = ctk_mouse_xtoc(mouse_x);
1064 myc = ctk_mouse_ytoc(mouse_y);
1065#endif /* CTK_CONF_MOUSE_SUPPORT */
1066
1067
adamdunkels66109622003-04-24 17:17:10 +00001068#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001069 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001070 if(ctk_arch_keyavail()
1071#if CTK_CONF_MOUSE_SUPPORT
1072 || mouse_moved || mouse_button_changed
1073#endif /* CTK_CONF_MOUSE_SUPPORT */
1074 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001075 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1076 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001078 }
adamdunkels66109622003-04-24 17:17:10 +00001079 } else
1080#endif /* CTK_CONF_SCREENSAVER */
1081 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001082#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001083 /* If there is any change in the mouse conditions, find out in
1084 which window the mouse pointer currently is in order to send
1085 the correct signals, or bring a window to focus. */
1086 if(mouse_moved || mouse_button_changed) {
1087 ctk_mouse_show();
1088 screensaver_timer = 0;
1089
1090 if(myc == 0) {
1091 /* Here we should do whatever needs to be done when the mouse
1092 moves around and clicks in the menubar. */
1093 if(mouse_clicked) {
1094 /* Find out which menu that the mouse pointer is in. Start
1095 with the ->next menu after the desktop menu. We assume
1096 that the menus start one character from the left screen
1097 side and that the desktop menu is farthest to the
1098 right. */
1099 menux = 1;
1100 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1101 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1102 break;
adamdunkelse0683312003-04-09 09:02:52 +00001103 }
adamdunkelsb2486562003-04-11 20:22:03 +00001104 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001105 }
adamdunkelsb2486562003-04-11 20:22:03 +00001106
1107 /* Also check desktop menu. */
1108 if(mxc >= width - 7 &&
1109 mxc <= width - 1) {
1110 menu = &desktopmenu;
1111 }
1112
1113 menus.open = menu;
1114 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001115 }
adamdunkelse0683312003-04-09 09:02:52 +00001116 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001117 --myc;
1118
1119 if(menus.open != NULL) {
1120 /* Do whatever needs to be done when a menu is open. */
1121
adamdunkelscf90b0d2003-08-09 13:34:16 +00001122 /* First check if the mouse pointer is in the currently open
1123 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001124 if(menus.open == &desktopmenu) {
1125 menux = width - CTK_CONF_MENUWIDTH;
1126 } else {
1127 menux = 1;
1128 for(menu = menus.menus->next; menu != menus.open;
1129 menu = menu->next) {
1130 menux += menu->titlelen;
1131 }
1132 }
1133
adamdunkelscf90b0d2003-08-09 13:34:16 +00001134 /* Find out which of the menu items the mouse is pointing
1135 to. */
adamdunkelsb2486562003-04-11 20:22:03 +00001136 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001137 if(myc <= menus.open->nitems) {
1138 menus.open->active = myc;
1139 } else {
1140 menus.open->active = menus.open->nitems - 1;
1141 }
adamdunkelsb2486562003-04-11 20:22:03 +00001142 }
1143
1144 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001145 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1146 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001147 redraw |= activate_menu();
1148 } else {
1149 lastmenu = menus.open;
1150 menus.open = NULL;
1151 redraw |= REDRAW_MENUPART;
1152 }
1153 } else {
1154 redraw |= REDRAW_MENUS;
1155 }
1156 } else {
1157
adamdunkels965e2922003-06-30 20:44:57 +00001158 /* Walk through the windows from top to bottom to see in
1159 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001160 if(dialog != NULL) {
1161 window = dialog;
1162 } else {
1163 for(window = windows; window != NULL; window = window->next) {
1164 /* Check if the mouse is within the window. */
1165 if(mxc >= window->x &&
1166 mxc <= window->x + window->w &&
1167 myc >= window->y &&
1168 myc <= window->y + window->h) {
1169 break;
1170 }
1171 }
1172 }
1173
1174
1175 /* If we didn't find any window, and there are no windows
1176 open, the mouse pointer will definately be within the
1177 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001178 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001179 window = &desktop_window;
1180 }
1181
adamdunkels965e2922003-06-30 20:44:57 +00001182 /* If the mouse pointer moves around outside of the
1183 currently focused window (or dialog), we should not have
1184 any focused widgets in the focused window so we make sure
1185 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001186 if(windows != NULL &&
1187 window != windows &&
1188 windows->focused != NULL){
1189 add_redrawwidget(windows->focused);
1190 windows->focused = NULL;
1191 redraw |= REDRAW_WIDGETS;
1192 }
1193
1194 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001195 /* If the mouse was clicked outside of the current window,
1196 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001197 if(dialog == NULL &&
1198 window != &desktop_window &&
1199 window != windows &&
1200 mouse_clicked) {
1201 /* Bring window to front. */
1202 ctk_window_open(window);
1203 redraw |= REDRAW_ALL;
1204 } else {
1205
adamdunkels965e2922003-06-30 20:44:57 +00001206 /* Find out which widget currently is under the mouse
1207 pointer and give it focus, unless it already has
1208 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001209 mxc = mxc - window->x - 1;
1210 myc = myc - window->y - 1;
1211
adamdunkels965e2922003-06-30 20:44:57 +00001212 /* See if the mouse pointer is on a widget. If so, it
1213 should be selected and, if the button is clicked,
1214 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001215 for(widget = window->active; widget != NULL;
1216 widget = widget->next) {
1217 if(mxc >= widget->x &&
1218 mxc <= widget->x + widget->w &&
1219 (myc == widget->y ||
1220 ((widget->type == CTK_WIDGET_BITMAP ||
1221 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1222 widget->type == CTK_WIDGET_ICON) &&
1223 (myc >= widget->y &&
1224 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1225 break;
1226 }
1227 }
1228
1229
adamdunkels58917a82003-04-18 00:18:38 +00001230 if(mouse_moved &&
1231 (window != &desktop_window ||
1232 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001233 dispatcher_emit(ctk_signal_pointer_move, NULL,
1234 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001235
adamdunkelsb2486562003-04-11 20:22:03 +00001236 if(window->focused != NULL &&
1237 widget != window->focused) {
1238 add_redrawwidget(window->focused);
1239 if(CTK_WIDGET_TYPE(window->focused) ==
1240 CTK_WIDGET_TEXTENTRY) {
1241 ((struct ctk_textentry *)(window->focused))->state =
1242 CTK_TEXTENTRY_NORMAL;
1243 }
1244 window->focused = NULL;
1245 }
1246 redraw |= REDRAW_WIDGETS;
1247 if(widget != NULL) {
1248 select_widget(widget);
1249 }
1250 }
1251
1252 if(mouse_button_changed) {
1253 dispatcher_emit(ctk_signal_pointer_button,
1254 (ek_data_t)mouse_button,
1255 window->owner);
1256 if(mouse_clicked && widget != NULL) {
1257 select_widget(widget);
1258 redraw |= activate(widget);
1259 }
1260 }
1261 }
1262 }
1263 }
adamdunkelsc4902862003-04-09 00:30:45 +00001264 }
1265 }
adamdunkels19a787c2003-04-09 09:22:24 +00001266#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001267
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001268 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001269
1270 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001271
1272 screensaver_timer = 0;
1273
adamdunkelsb2486562003-04-11 20:22:03 +00001274 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001275
1276 if(dialog != NULL) {
1277 window = dialog;
1278 } else if(windows != NULL) {
1279 window = windows;
1280 } else {
1281 window = &desktop_window;
1282 }
1283 widget = window->focused;
1284
1285
1286 if(widget != NULL &&
1287 widget->type == CTK_WIDGET_TEXTENTRY &&
1288 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1289 textentry_input(c, (struct ctk_textentry *)widget);
1290 add_redrawwidget(widget);
1291#if CTK_CONF_MENUS
1292 } else if(menus.open != NULL) {
1293 redraw |= menus_input(c);
1294#endif /* CTK_CONF_MENUS */
1295 } else {
1296 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001297 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001298 switch_focus_widget(DOWN);
1299 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001300 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001301 switch_focus_widget(UP);
1302 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001303#if CTK_CONF_MENUS
1304 case CTK_CONF_MENU_KEY:
1305 if(dialog == NULL) {
1306 if(lastmenu == NULL) {
1307 menus.open = menus.menus;
1308 } else {
1309 menus.open = lastmenu;
1310 }
1311 menus.open->active = 0;
1312 redraw |= REDRAW_MENUS;
1313 }
1314 break;
1315#endif /* CTK_CONF_MENUS */
1316 case CTK_CONF_WINDOWSWITCH_KEY:
1317 if(windows != NULL) {
1318 for(window = windows; window->next != NULL;
1319 window = window->next);
1320 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001321 }
1322 break;
1323 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001324 if(c == CH_ENTER &&
1325 widget != NULL) {
1326 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001327 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001328 add_redrawwidget(widget);
1329 if(widget != NULL &&
1330 widget->type == CTK_WIDGET_TEXTENTRY) {
1331 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1332 textentry_input(c, (struct ctk_textentry *)widget);
1333 } else {
1334 window->focused = NULL;
1335 dispatcher_emit(ctk_signal_keypress, (void *)c,
1336 window->owner);
1337 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001338 }
1339 break;
1340 }
1341 }
1342
1343 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001344 widgetptr = redraw_widgets;
1345 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1346 /* if(redraw_widgets[i] != NULL) {
1347 ctk_widget_redraw(redraw_widgets[i]);
1348 }
1349 redraw_widgets[i] = NULL;*/
1350 ctk_widget_redraw(*widgetptr);
1351 *widgetptr = NULL;
1352 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001353 }
1354 redraw &= ~REDRAW_WIDGETS;
1355 redraw_widgetptr = 0;
1356 }
1357 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001358#if CTK_CONF_WINDOWMOVE
1359 } else if(mode == CTK_MODE_WINDOWMOVE) {
1360
1361 redraw = 0;
1362
1363 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001364
1365#if CTK_CONF_MOUSE_SUPPORT
1366
1367 /* If the mouse has moved, we move the window as well. */
1368 if(mouse_moved) {
1369
1370 if(window->w + mxc + 2 >= width) {
1371 window->x = width - 2 - window->w;
1372 } else {
1373 window->x = mxc;
1374 }
1375
1376 if(window->h + myc + 2 >= height) {
1377 window->y = height - 2 - window->h;
1378 } else {
1379 window->y = myc;
1380 }
1381 if(window->y > 0) {
1382 --window->y;
1383 }
1384
1385 redraw = REDRAW_ALL;
1386 }
1387
1388 /* Check if the mouse has been clicked, and stop moving the window
1389 if so. */
1390 if(mouse_button_changed &&
1391 mouse_button == 0) {
1392 mode = CTK_MODE_NORMAL;
1393 redraw = REDRAW_ALL;
1394 }
1395#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001396
1397 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1398
1399 screensaver_timer = 0;
1400
1401 c = ctk_arch_getkey();
1402
1403 switch(c) {
1404 case CH_CURS_RIGHT:
1405 ++window->x;
1406 if(window->x + window->w + 1 >= width) {
1407 --window->x;
1408 }
1409 redraw = REDRAW_ALL;
1410 break;
1411 case CH_CURS_LEFT:
1412 if(window->x > 0) {
1413 --window->x;
1414 }
1415 redraw = REDRAW_ALL;
1416 break;
1417 case CH_CURS_DOWN:
1418 ++window->y;
1419 if(window->y + window->h + 2 >= height) {
1420 --window->y;
1421 }
1422 redraw = REDRAW_ALL;
1423 break;
1424 case CH_CURS_UP:
1425 if(window->y > 0) {
1426 --window->y;
1427 }
1428 redraw = REDRAW_ALL;
1429 break;
1430 case CH_ENTER:
1431 case CH_ESC:
1432 mode = CTK_MODE_NORMAL;
1433 redraw = REDRAW_ALL;
1434 break;
1435 }
1436 }
adamdunkelsb2486562003-04-11 20:22:03 +00001437 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001438 do_redraw_all(1, height);
1439 }
adamdunkelsb2486562003-04-11 20:22:03 +00001440 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001441#endif /* CTK_CONF_WINDOWMOVE */
1442 }
adamdunkelsb2486562003-04-11 20:22:03 +00001443
1444 if(redraw & REDRAW_ALL) {
1445 do_redraw_all(1, height);
1446#if CTK_CONF_MENUS
1447 } else if(redraw & REDRAW_MENUPART) {
1448 do_redraw_all(1, maxnitems + 1);
1449 } else if(redraw & REDRAW_MENUS) {
1450 ctk_draw_menus(&menus);
1451#endif /* CTK_CONF_MENUS */
1452 } else if(redraw & REDRAW_FOCUS) {
1453 if(dialog != NULL) {
1454 ctk_window_redraw(dialog);
1455 } else if(windows != NULL) {
1456 ctk_window_redraw(windows);
1457 } else {
1458 ctk_window_redraw(&desktop_window);
1459 }
1460 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001461 widgetptr = redraw_widgets;
1462 /* for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkelsb2486562003-04-11 20:22:03 +00001463 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001464 }*/
1465 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1466 ctk_widget_redraw(*widgetptr);
1467 *widgetptr = NULL;
1468 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001469 }
1470 }
1471 redraw = 0;
1472 redraw_widgetptr = 0;
1473
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001474}
1475/*-----------------------------------------------------------------------------------*/
adamdunkelscf90b0d2003-08-09 13:34:16 +00001476#if 0
adamdunkels78c03dc2003-04-09 13:45:05 +00001477static
1478DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001479{
adamdunkels78c03dc2003-04-09 13:45:05 +00001480 DISPATCHER_SIGHANDLER_ARGS(s, data);
1481
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001482 if(s == ctk_signal_timer) {
1483 if(mode == CTK_MODE_NORMAL) {
1484 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001485 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001486#if CTK_CONF_SCREENSAVER
1487 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1488 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001489#ifdef CTK_SCREENSAVER_INIT
1490 CTK_SCREENSAVER_INIT();
1491#endif /* CTK_SCREENSAVER_INIT */
1492 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001493#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001494 screensaver_timer = 0;
1495 }
1496 }
1497 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1498 }
1499}
adamdunkelscf90b0d2003-08-09 13:34:16 +00001500#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001501/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001502