blob: 4be2980554920f613ac3fa6c57f0ac7749e77523 [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 *
adamdunkels9795b2e2003-08-09 23:32:37 +000035 * $Id: ctk.c,v 1.24 2003/08/09 23:32:37 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;
382#endif /* CTK_CONF_MENUS */
383}
384/*-----------------------------------------------------------------------------------*/
385void
386ctk_menu_remove(struct ctk_menu *menu)
387{
388#if CTK_CONF_MENUS
389 struct ctk_menu *m;
390
391 for(m = menus.menus; m->next != NULL; m = m->next) {
392 if(m->next == menu) {
393 m->next = menu->next;
394 return;
395 }
396 }
397#endif /* CTK_CONF_MENUS */
398}
399/*-----------------------------------------------------------------------------------*/
400static void
401do_redraw_all(unsigned char clipy1, unsigned char clipy2)
402{
403 struct ctk_window *w;
404 struct ctk_widget *widget;
405
406 if(mode != CTK_MODE_NORMAL &&
407 mode != CTK_MODE_WINDOWMOVE) {
408 return;
409 }
410
411 ctk_draw_clear(clipy1, clipy2);
412
413 /* Draw widgets in root window */
414 for(widget = desktop_window.active;
415 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000416 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000417 }
418
419 /* Draw windows */
420 if(windows != NULL) {
421 /* Find the last window.*/
422 for(w = windows; w->next != NULL; w = w->next);
423
424 /* Draw the windows from back to front. */
425 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000426 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000427 ctk_draw_window(w, 0, clipy1, clipy2);
428 }
429 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000430 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000431 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
432 }
433
434 /* Draw dialog (if any) */
435 if(dialog != NULL) {
436 ctk_draw_dialog(dialog);
437 }
438
439#if CTK_CONF_MENUS
440 ctk_draw_menus(&menus);
441#endif /* CTK_CONF_MENUS */
442}
443/*-----------------------------------------------------------------------------------*/
444void
adamdunkels965e2922003-06-30 20:44:57 +0000445ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000446{
447 if(DISPATCHER_CURRENT() == ctkid) {
448 if(mode == CTK_MODE_NORMAL ||
449 mode == CTK_MODE_WINDOWMOVE) {
450 do_redraw_all(1, height);
451 }
452 } else {
453 redraw |= REDRAW_ALL;
454 }
455}
456/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000457void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458ctk_window_redraw(struct ctk_window *w)
459{
460 /* Only redraw the window if it is a dialog or if it is the foremost
461 window. */
462 if(mode != CTK_MODE_NORMAL) {
463 return;
464 }
465
466 if(w == dialog) {
467 ctk_draw_dialog(w);
468 } else if(dialog == NULL &&
469#if CTK_CONF_MENUS
470 menus.open == NULL &&
471#endif /* CTK_CONF_MENUS */
472 windows == w) {
473 ctk_draw_window(w, CTK_FOCUS_WINDOW,
474 0, height);
475 }
476}
477/*-----------------------------------------------------------------------------------*/
478static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000479window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000480 unsigned char w, unsigned char h,
481 char *title)
482{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000483
484 if(w >= width - 2) {
485 window->x = 0;
486 } else {
487 window->x = (width - w - 2) / 2;
488 }
489 if(h >= height - 3) {
490 window->y = 0;
491 } else {
492 window->y = (height - h - 1) / 2;
493 }
494
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000495 window->w = w;
496 window->h = h;
497 window->title = title;
498 if(title != NULL) {
499 window->titlelen = strlen(title);
500 } else {
501 window->titlelen = 0;
502 }
503 window->next = window->prev = NULL;
504 window->owner = DISPATCHER_CURRENT();
505 window->active = window->inactive = window->focused = NULL;
506}
507/*-----------------------------------------------------------------------------------*/
508void
509ctk_window_new(struct ctk_window *window,
510 unsigned char w, unsigned char h,
511 char *title)
512{
513 window_new(window, w, h, title);
514
515 make_windowbuttons(window);
516}
517/*-----------------------------------------------------------------------------------*/
518void
adamdunkelsd07a5422003-04-05 12:22:35 +0000519ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000520 unsigned char w, unsigned char h)
521{
522 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000523}
adamdunkels9795b2e2003-08-09 23:32:37 +0000524/*-----------------------------------------------------------------------------------*/void
adamdunkelsd07a5422003-04-05 12:22:35 +0000525ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526 char *title)
527{
528#if CTK_CONF_MENUS
529 menu->next = NULL;
530 menu->title = title;
531 menu->titlelen = strlen(title);
532 menu->active = 0;
533 menu->nitems = 0;
534#endif /* CTK_CONF_MENUS */
535}
536/*-----------------------------------------------------------------------------------*/
537unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000538ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000539 char *name)
540{
541#if CTK_CONF_MENUS
542 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
543 return 0;
544 }
545 menu->items[menu->nitems].title = name;
546 menu->items[menu->nitems].titlelen = strlen(name);
547 return menu->nitems++;
548#else
549 return 0;
550#endif /* CTK_CONF_MENUS */
551}
552/*-----------------------------------------------------------------------------------*/
553static void
554add_redrawwidget(struct ctk_widget *w)
555{
556 static unsigned char i;
557
558 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
559 redraw |= REDRAW_FOCUS;
560 } else {
561 redraw |= REDRAW_WIDGETS;
562 /* Check if it is in the queue already. If so, we don't add it
563 again. */
564 for(i = 0; i < redraw_widgetptr; ++i) {
565 if(redraw_widgets[i] == w) {
566 return;
567 }
568 }
569 redraw_widgets[redraw_widgetptr++] = w;
570 }
571}
572/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000573void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000574ctk_widget_redraw(struct ctk_widget *widget)
575{
576 struct ctk_window *window;
577
adamdunkels9f667f22003-04-16 18:29:19 +0000578 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000579 return;
580 }
581
582 /* If this function isn't called by CTK itself, we only queue the
583 redraw request. */
584 if(DISPATCHER_CURRENT() != ctkid) {
585 redraw |= REDRAW_WIDGETS;
586 add_redrawwidget(widget);
587 } else {
588
589 /* Only redraw widgets that are in the foremost window. If we
590 would allow redrawing widgets in non-focused windows, we would
591 have to redraw all the windows that cover the non-focused
592 window as well, which would lead to flickering.
593
594 Also, we avoid drawing any widgets when the menus are active.
595 */
596
597#if CTK_CONF_MENUS
598 if(menus.open == NULL)
599#endif /* CTK_CONF_MENUS */
600 {
601 window = widget->window;
602 if(window == dialog) {
603 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels47efbc42003-08-07 00:03:26 +0000604 } else if(dialog == NULL &&
adamdunkels9795b2e2003-08-09 23:32:37 +0000605 (window == windows ||
606 window == &desktop_window)) {
adamdunkels66109622003-04-24 17:17:10 +0000607 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000608 }
609 }
610 }
611}
612/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000613void
adamdunkelsd07a5422003-04-05 12:22:35 +0000614ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
615 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000616{
617 if(widget->type == CTK_WIDGET_LABEL ||
618 widget->type == CTK_WIDGET_SEPARATOR) {
619 widget->next = window->inactive;
620 window->inactive = widget;
621 widget->window = window;
622 } else {
623 widget->next = window->active;
624 window->active = widget;
625 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000626 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000627 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000628 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000629 }
630}
631/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000632unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000633ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000634{
635 return ctk_draw_width();
636}
637/*-----------------------------------------------------------------------------------*/
638unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000639ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000640{
641 return ctk_draw_height();
642}
643/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000644static void
adamdunkelsb2486562003-04-11 20:22:03 +0000645select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000646{
647 struct ctk_window *window;
648
649 window = focus->window;
650
651 if(focus != window->focused) {
652 window->focused = focus;
653 /* The operation changed the focus, so we emit a "hover" signal
654 for those widgets that support it. */
655
656 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
657 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
658 window->owner);
659 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
660 dispatcher_emit(ctk_signal_button_hover, window->focused,
661 window->owner);
662 }
663
664 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000665
666 dispatcher_emit(ctk_signal_widget_select, focus,
667 focus->window->owner);
668
adamdunkelse0683312003-04-09 09:02:52 +0000669 }
670
671}
672/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000673#define UP 0
674#define DOWN 1
675#define LEFT 2
676#define RIGHT 3
adamdunkels9795b2e2003-08-09 23:32:37 +0000677static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000678switch_focus_widget(unsigned char direction)
679{
680 register struct ctk_window *window;
681 register struct ctk_widget *focus;
682 struct ctk_widget *widget;
683
684
685 if(dialog != NULL) {
686 window = dialog;
687 } else {
688 window = windows;
689 }
690
691 /* If there are no windows open, we move focus around between the
692 icons on the root window instead. */
693 if(window == NULL) {
694 window = &desktop_window;
695 }
696
697 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000698 if(focus == NULL) {
699 focus = window->active;
700 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000701 add_redrawwidget(focus);
702
703 if((direction & 1) == 0) {
704 /* Move focus "up" */
705 focus = focus->next;
706 } else {
707 /* Move focus "down" */
708 for(widget = window->active;
709 widget != NULL; widget = widget->next) {
710 if(widget->next == focus) {
711 break;
712 }
713 }
714 focus = widget;
715 if(focus == NULL) {
716 if(window->active != NULL) {
717 for(focus = window->active;
718 focus->next != NULL; focus = focus->next);
719 }
720 }
721 }
722 if(focus == NULL) {
723 focus = window->active;
724 }
adamdunkelse0683312003-04-09 09:02:52 +0000725
adamdunkelsb2486562003-04-11 20:22:03 +0000726 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000727}
728/*-----------------------------------------------------------------------------------*/
729#if CTK_CONF_MENUS
730static void
731switch_open_menu(unsigned char rightleft)
732{
733 struct ctk_menu *menu;
734
735 if(rightleft == 0) {
736 /* Move right */
737 for(menu = menus.menus; menu != NULL; menu = menu->next) {
738 if(menu->next == menus.open) {
739 break;
740 }
741 }
742 lastmenu = menus.open;
743 menus.open = menu;
744 if(menus.open == NULL) {
745 for(menu = menus.menus;
746 menu->next != NULL; menu = menu->next);
747 menus.open = menu;
748 }
749 } else {
750 /* Move to left */
751 lastmenu = menus.open;
752 menus.open = menus.open->next;
753 if(menus.open == NULL) {
754 menus.open = menus.menus;
755 }
756 }
757
adamdunkels66109622003-04-24 17:17:10 +0000758 menus.open->active = 0;
759
760 /* if(menus.open->nitems > maxnitems) {
761 maxnitems = menus.open->nitems;
762 }*/
763
adamdunkels965e2922003-06-30 20:44:57 +0000764 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000765}
766/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000767static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000768switch_menu_item(unsigned char updown)
769{
770 register struct ctk_menu *m;
771
772 m = menus.open;
773
774 if(updown == 0) {
775 /* Move up */
776 if(m->active == 0) {
777 m->active = m->nitems - 1;
778 } else {
779 --m->active;
780 if(m->items[m->active].title[0] == '-') {
781 --m->active;
782 }
783 }
784 } else {
785 /* Move down */
786 if(m->active >= m->nitems - 1) {
787 m->active = 0;
788 } else {
789 ++m->active;
790 if(m->items[m->active].title[0] == '-') {
791 ++m->active;
792 }
793 }
794 }
795
796}
797#endif /* CTK_CONF_MENUS */
798/*-----------------------------------------------------------------------------------*/
799static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000800activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000801{
802 static unsigned char len;
803
804 if(w->type == CTK_WIDGET_BUTTON) {
805 if(w == (struct ctk_widget *)&windows->closebutton) {
806#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000807 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808 ctk_window_close(windows);
809 return REDRAW_ALL;
810#endif /* CTK_CONF_WINDOWCLOSE */
811 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
812#if CTK_CONF_WINDOWCLOSE
813 mode = CTK_MODE_WINDOWMOVE;
814#endif /* CTK_CONF_WINDOWCLOSE */
815 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000816 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000817 w->window->owner);
818 }
819#if CTK_CONF_ICONS
820 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000821 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000822 w->widget.icon.owner);
823#endif /* CTK_CONF_ICONS */
824 } else if(w->type == CTK_WIDGET_HYPERLINK) {
825 dispatcher_emit(ctk_signal_hyperlink_activate, w,
826 DISPATCHER_BROADCAST);
827 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
828 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
829 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
830 len = strlen(w->widget.textentry.text);
831 if(w->widget.textentry.xpos > len) {
832 w->widget.textentry.xpos = len;
833 }
834 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
835 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
836 }
837 add_redrawwidget(w);
838 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000839 } else {
840 dispatcher_emit(ctk_signal_widget_activate, w,
841 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000842 }
843 return REDRAW_NONE;
844}
845/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000846static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000847textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000848 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000850 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851 static unsigned char len, txpos, typos, tlen;
852
853 txpos = t->xpos;
854 typos = t->ypos;
855 tlen = t->len;
856
857 cptr = &t->text[txpos + typos * tlen];
858
859 switch(c) {
860 case CH_CURS_LEFT:
861 if(txpos > 0) {
862 --txpos;
863 }
864 break;
865
866 case CH_CURS_RIGHT:
867 if(txpos < tlen &&
868 *cptr != 0) {
869 ++txpos;
870 }
871 break;
872
873 case CH_CURS_UP:
874#if CTK_CONF_TEXTENTRY_MULTILINE
875 if(t->h == 1) {
876 txpos = 0;
877 } else {
878 if(typos > 0) {
879 --typos;
880 } else {
881 t->state = CTK_TEXTENTRY_NORMAL;
882 }
883 }
884#else
885 txpos = 0;
886#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
887 break;
888
889 case CH_CURS_DOWN:
890#if CTK_CONF_TEXTENTRY_MULTILINE
891 if(t->h == 1) {
892 txpos = strlen(t->text);
893 } else {
894 if(typos < t->h - 1) {
895 ++typos;
896 } else {
897 t->state = CTK_TEXTENTRY_NORMAL;
898 }
899 }
900#else
901 txpos = strlen(t->text);
902#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
903 break;
904
905 case CH_ENTER:
906#if CTK_CONF_TEXTENTRY_MULTILINE
907 if(t->h == 1) {
908 t->state = CTK_TEXTENTRY_NORMAL;
909 } else {
910 if(typos < t->h - 1) {
911 ++typos;
912 txpos = 0;
913 } else {
914 t->state = CTK_TEXTENTRY_NORMAL;
915 }
916 }
917#else
918 t->state = CTK_TEXTENTRY_NORMAL;
919#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
920 break;
921
adamdunkels9795b2e2003-08-09 23:32:37 +0000922 case CTK_CONF_WIDGETDOWN_KEY:
923 t->state = CTK_TEXTENTRY_NORMAL;
924 switch_focus_widget(DOWN);
925 break;
926 case CTK_CONF_WIDGETUP_KEY:
927 t->state = CTK_TEXTENTRY_NORMAL;
928 switch_focus_widget(UP);
929 break;
930
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000931 default:
932 len = tlen - txpos - 1;
933 if(c == CH_DEL) {
934 if(txpos > 0 && len > 0) {
935 strncpy(cptr - 1, cptr,
936 len);
937 *(cptr + len - 1) = 0;
938 --txpos;
939 }
940 } else {
941 if(len > 0) {
942 cptr2 = cptr + len - 1;
943 while(cptr2 + 1 > cptr) {
944 *(cptr2 + 1) = *cptr2;
945 --cptr2;
946 }
947
948 *cptr = c;
949 ++txpos;
950 }
951 }
952 break;
953 }
954
955 t->xpos = txpos;
956 t->ypos = typos;
957}
958/*-----------------------------------------------------------------------------------*/
959#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000960static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000961activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000962{
963 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000964
965 lastmenu = menus.open;
966 if(menus.open == &desktopmenu) {
967 for(w = windows; w != NULL; w = w->next) {
968 if(w->title == desktopmenu.items[desktopmenu.active].title) {
969 ctk_window_open(w);
970 menus.open = NULL;
971 return REDRAW_ALL;
972 }
973 }
974 } else {
975 dispatcher_emit(ctk_signal_menu_activate, menus.open,
976 DISPATCHER_BROADCAST);
977 }
978 menus.open = NULL;
979 return REDRAW_MENUPART;
980}
981/*-----------------------------------------------------------------------------------*/
982static unsigned char
983menus_input(ctk_arch_key_t c)
984{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000985
986 if(menus.open->nitems > maxnitems) {
987 maxnitems = menus.open->nitems;
988 }
989
990
991 switch(c) {
992 case CH_CURS_RIGHT:
993 switch_open_menu(1);
994
995 return REDRAW_MENUPART;
996
997 case CH_CURS_DOWN:
998 switch_menu_item(1);
999 return REDRAW_MENUS;
1000
1001 case CH_CURS_LEFT:
1002 switch_open_menu(0);
1003 return REDRAW_MENUPART;
1004
1005 case CH_CURS_UP:
1006 switch_menu_item(0);
1007 return REDRAW_MENUS;
1008
1009 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001010 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001011
adamdunkels88ed9c42003-03-28 12:10:09 +00001012 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001013 lastmenu = menus.open;
1014 menus.open = NULL;
1015 return REDRAW_MENUPART;
1016 }
adamdunkelsb2486562003-04-11 20:22:03 +00001017
1018 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001019}
1020#endif /* CTK_CONF_MENUS */
1021/*-----------------------------------------------------------------------------------*/
1022static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001023timer(void)
1024{
1025 if(mode == CTK_MODE_NORMAL) {
1026 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001027 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001028#if CTK_CONF_SCREENSAVER
1029 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1030 DISPATCHER_BROADCAST);
1031#ifdef CTK_SCREENSAVER_INIT
1032 CTK_SCREENSAVER_INIT();
1033#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001034
adamdunkelscf90b0d2003-08-09 13:34:16 +00001035#endif /* CTK_CONF_SCREENSAVER */
1036 screensaver_timer = 0;
1037 }
1038 }
1039}
1040/*-----------------------------------------------------------------------------------*/
1041static void
adamdunkelsc4902862003-04-09 00:30:45 +00001042ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001043{
1044 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001045 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001046 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001047 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001048 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001049#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001050 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1051 mouse_clicked;
1052 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001053 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001054
adamdunkels19a787c2003-04-09 09:22:24 +00001055#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001056
1057
1058 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001059
adamdunkels9795b2e2003-08-09 23:32:37 +00001060 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001061 timer();
1062 start = current;
1063 }
1064
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001065#if CTK_CONF_MENUS
1066 if(menus.open != NULL) {
1067 maxnitems = menus.open->nitems;
1068 } else {
1069 maxnitems = 0;
1070 }
1071#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001072
1073#if CTK_CONF_MOUSE_SUPPORT
1074 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1075
1076 /* See if there is any change in the buttons. */
1077 if(ctk_mouse_button() != mouse_button) {
1078 mouse_button = ctk_mouse_button();
1079 mouse_button_changed = 1;
1080 if(mouse_button == 0) {
1081 mouse_clicked = 1;
1082 }
1083 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001084
adamdunkelsb2486562003-04-11 20:22:03 +00001085 /* Check if the mouse pointer has moved. */
1086 if(ctk_mouse_x() != mouse_x ||
1087 ctk_mouse_y() != mouse_y) {
1088 mouse_x = ctk_mouse_x();
1089 mouse_y = ctk_mouse_y();
1090 mouse_moved = 1;
1091 }
1092
1093 mxc = ctk_mouse_xtoc(mouse_x);
1094 myc = ctk_mouse_ytoc(mouse_y);
1095#endif /* CTK_CONF_MOUSE_SUPPORT */
1096
1097
adamdunkels66109622003-04-24 17:17:10 +00001098#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001099 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001100 if(ctk_arch_keyavail()
1101#if CTK_CONF_MOUSE_SUPPORT
1102 || mouse_moved || mouse_button_changed
1103#endif /* CTK_CONF_MOUSE_SUPPORT */
1104 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001105 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1106 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001107 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001108 }
adamdunkels66109622003-04-24 17:17:10 +00001109 } else
1110#endif /* CTK_CONF_SCREENSAVER */
1111 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001112#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001113 /* If there is any change in the mouse conditions, find out in
1114 which window the mouse pointer currently is in order to send
1115 the correct signals, or bring a window to focus. */
1116 if(mouse_moved || mouse_button_changed) {
1117 ctk_mouse_show();
1118 screensaver_timer = 0;
1119
1120 if(myc == 0) {
1121 /* Here we should do whatever needs to be done when the mouse
1122 moves around and clicks in the menubar. */
1123 if(mouse_clicked) {
1124 /* Find out which menu that the mouse pointer is in. Start
1125 with the ->next menu after the desktop menu. We assume
1126 that the menus start one character from the left screen
1127 side and that the desktop menu is farthest to the
1128 right. */
1129 menux = 1;
1130 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1131 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1132 break;
adamdunkelse0683312003-04-09 09:02:52 +00001133 }
adamdunkelsb2486562003-04-11 20:22:03 +00001134 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001135 }
adamdunkelsb2486562003-04-11 20:22:03 +00001136
1137 /* Also check desktop menu. */
1138 if(mxc >= width - 7 &&
1139 mxc <= width - 1) {
1140 menu = &desktopmenu;
1141 }
1142
1143 menus.open = menu;
1144 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001145 }
adamdunkelse0683312003-04-09 09:02:52 +00001146 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001147 --myc;
1148
1149 if(menus.open != NULL) {
1150 /* Do whatever needs to be done when a menu is open. */
1151
adamdunkelscf90b0d2003-08-09 13:34:16 +00001152 /* First check if the mouse pointer is in the currently open
1153 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001154 if(menus.open == &desktopmenu) {
1155 menux = width - CTK_CONF_MENUWIDTH;
1156 } else {
1157 menux = 1;
1158 for(menu = menus.menus->next; menu != menus.open;
1159 menu = menu->next) {
1160 menux += menu->titlelen;
1161 }
1162 }
1163
adamdunkelscf90b0d2003-08-09 13:34:16 +00001164 /* Find out which of the menu items the mouse is pointing
1165 to. */
adamdunkelsb2486562003-04-11 20:22:03 +00001166 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001167 if(myc <= menus.open->nitems) {
1168 menus.open->active = myc;
1169 } else {
1170 menus.open->active = menus.open->nitems - 1;
1171 }
adamdunkelsb2486562003-04-11 20:22:03 +00001172 }
1173
1174 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001175 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1176 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001177 redraw |= activate_menu();
1178 } else {
1179 lastmenu = menus.open;
1180 menus.open = NULL;
1181 redraw |= REDRAW_MENUPART;
1182 }
1183 } else {
1184 redraw |= REDRAW_MENUS;
1185 }
1186 } else {
1187
adamdunkels965e2922003-06-30 20:44:57 +00001188 /* Walk through the windows from top to bottom to see in
1189 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001190 if(dialog != NULL) {
1191 window = dialog;
1192 } else {
1193 for(window = windows; window != NULL; window = window->next) {
1194 /* Check if the mouse is within the window. */
1195 if(mxc >= window->x &&
1196 mxc <= window->x + window->w &&
1197 myc >= window->y &&
1198 myc <= window->y + window->h) {
1199 break;
1200 }
1201 }
1202 }
1203
1204
1205 /* If we didn't find any window, and there are no windows
1206 open, the mouse pointer will definately be within the
1207 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001208 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001209 window = &desktop_window;
1210 }
1211
adamdunkels965e2922003-06-30 20:44:57 +00001212 /* If the mouse pointer moves around outside of the
1213 currently focused window (or dialog), we should not have
1214 any focused widgets in the focused window so we make sure
1215 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001216 if(windows != NULL &&
1217 window != windows &&
1218 windows->focused != NULL){
1219 add_redrawwidget(windows->focused);
1220 windows->focused = NULL;
1221 redraw |= REDRAW_WIDGETS;
1222 }
1223
1224 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001225 /* If the mouse was clicked outside of the current window,
1226 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001227 if(dialog == NULL &&
1228 window != &desktop_window &&
1229 window != windows &&
1230 mouse_clicked) {
1231 /* Bring window to front. */
1232 ctk_window_open(window);
1233 redraw |= REDRAW_ALL;
1234 } else {
1235
adamdunkels965e2922003-06-30 20:44:57 +00001236 /* Find out which widget currently is under the mouse
1237 pointer and give it focus, unless it already has
1238 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001239 mxc = mxc - window->x - 1;
1240 myc = myc - window->y - 1;
1241
adamdunkels965e2922003-06-30 20:44:57 +00001242 /* See if the mouse pointer is on a widget. If so, it
1243 should be selected and, if the button is clicked,
1244 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001245 for(widget = window->active; widget != NULL;
1246 widget = widget->next) {
1247 if(mxc >= widget->x &&
1248 mxc <= widget->x + widget->w &&
1249 (myc == widget->y ||
1250 ((widget->type == CTK_WIDGET_BITMAP ||
1251 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1252 widget->type == CTK_WIDGET_ICON) &&
1253 (myc >= widget->y &&
1254 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1255 break;
1256 }
1257 }
1258
1259
adamdunkels58917a82003-04-18 00:18:38 +00001260 if(mouse_moved &&
1261 (window != &desktop_window ||
1262 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001263 dispatcher_emit(ctk_signal_pointer_move, NULL,
1264 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001265
adamdunkelsb2486562003-04-11 20:22:03 +00001266 if(window->focused != NULL &&
1267 widget != window->focused) {
1268 add_redrawwidget(window->focused);
1269 if(CTK_WIDGET_TYPE(window->focused) ==
1270 CTK_WIDGET_TEXTENTRY) {
1271 ((struct ctk_textentry *)(window->focused))->state =
1272 CTK_TEXTENTRY_NORMAL;
1273 }
1274 window->focused = NULL;
1275 }
1276 redraw |= REDRAW_WIDGETS;
1277 if(widget != NULL) {
1278 select_widget(widget);
1279 }
1280 }
1281
1282 if(mouse_button_changed) {
1283 dispatcher_emit(ctk_signal_pointer_button,
1284 (ek_data_t)mouse_button,
1285 window->owner);
1286 if(mouse_clicked && widget != NULL) {
1287 select_widget(widget);
1288 redraw |= activate(widget);
1289 }
1290 }
1291 }
1292 }
1293 }
adamdunkelsc4902862003-04-09 00:30:45 +00001294 }
1295 }
adamdunkels19a787c2003-04-09 09:22:24 +00001296#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001297
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001298 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001299
1300 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001301
1302 screensaver_timer = 0;
1303
adamdunkelsb2486562003-04-11 20:22:03 +00001304 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001305
1306 if(dialog != NULL) {
1307 window = dialog;
1308 } else if(windows != NULL) {
1309 window = windows;
1310 } else {
1311 window = &desktop_window;
1312 }
1313 widget = window->focused;
1314
1315
1316 if(widget != NULL &&
1317 widget->type == CTK_WIDGET_TEXTENTRY &&
1318 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1319 textentry_input(c, (struct ctk_textentry *)widget);
1320 add_redrawwidget(widget);
1321#if CTK_CONF_MENUS
1322 } else if(menus.open != NULL) {
1323 redraw |= menus_input(c);
1324#endif /* CTK_CONF_MENUS */
1325 } else {
1326 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001327 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001328 switch_focus_widget(DOWN);
1329 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001330 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001331 switch_focus_widget(UP);
1332 break;
1333 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001334 if(widget != NULL) {
1335 redraw |= activate(widget);
1336 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001337 break;
1338#if CTK_CONF_MENUS
1339 case CTK_CONF_MENU_KEY:
1340 if(dialog == NULL) {
1341 if(lastmenu == NULL) {
1342 menus.open = menus.menus;
1343 } else {
1344 menus.open = lastmenu;
1345 }
1346 menus.open->active = 0;
1347 redraw |= REDRAW_MENUS;
1348 }
1349 break;
1350#endif /* CTK_CONF_MENUS */
1351 case CTK_CONF_WINDOWSWITCH_KEY:
1352 if(windows != NULL) {
1353 for(window = windows; window->next != NULL;
1354 window = window->next);
1355 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001356 }
1357 break;
1358 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001359 if(widget != NULL &&
1360 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001361 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1362 textentry_input(c, (struct ctk_textentry *)widget);
1363 add_redrawwidget(widget);
1364 } else {
1365 dispatcher_emit(ctk_signal_keypress, (void *)c,
1366 window->owner);
1367 }
1368 break;
1369 }
1370 }
1371
1372 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001373 widgetptr = redraw_widgets;
1374 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1375 /* if(redraw_widgets[i] != NULL) {
1376 ctk_widget_redraw(redraw_widgets[i]);
1377 }
1378 redraw_widgets[i] = NULL;*/
1379 ctk_widget_redraw(*widgetptr);
1380 *widgetptr = NULL;
1381 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001382 }
1383 redraw &= ~REDRAW_WIDGETS;
1384 redraw_widgetptr = 0;
1385 }
1386 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001387#if CTK_CONF_WINDOWMOVE
1388 } else if(mode == CTK_MODE_WINDOWMOVE) {
1389
1390 redraw = 0;
1391
1392 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001393
1394#if CTK_CONF_MOUSE_SUPPORT
1395
1396 /* If the mouse has moved, we move the window as well. */
1397 if(mouse_moved) {
1398
1399 if(window->w + mxc + 2 >= width) {
1400 window->x = width - 2 - window->w;
1401 } else {
1402 window->x = mxc;
1403 }
1404
1405 if(window->h + myc + 2 >= height) {
1406 window->y = height - 2 - window->h;
1407 } else {
1408 window->y = myc;
1409 }
1410 if(window->y > 0) {
1411 --window->y;
1412 }
1413
1414 redraw = REDRAW_ALL;
1415 }
1416
1417 /* Check if the mouse has been clicked, and stop moving the window
1418 if so. */
1419 if(mouse_button_changed &&
1420 mouse_button == 0) {
1421 mode = CTK_MODE_NORMAL;
1422 redraw = REDRAW_ALL;
1423 }
1424#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001425
1426 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1427
1428 screensaver_timer = 0;
1429
1430 c = ctk_arch_getkey();
1431
1432 switch(c) {
1433 case CH_CURS_RIGHT:
1434 ++window->x;
1435 if(window->x + window->w + 1 >= width) {
1436 --window->x;
1437 }
1438 redraw = REDRAW_ALL;
1439 break;
1440 case CH_CURS_LEFT:
1441 if(window->x > 0) {
1442 --window->x;
1443 }
1444 redraw = REDRAW_ALL;
1445 break;
1446 case CH_CURS_DOWN:
1447 ++window->y;
1448 if(window->y + window->h + 2 >= height) {
1449 --window->y;
1450 }
1451 redraw = REDRAW_ALL;
1452 break;
1453 case CH_CURS_UP:
1454 if(window->y > 0) {
1455 --window->y;
1456 }
1457 redraw = REDRAW_ALL;
1458 break;
1459 case CH_ENTER:
1460 case CH_ESC:
1461 mode = CTK_MODE_NORMAL;
1462 redraw = REDRAW_ALL;
1463 break;
1464 }
1465 }
adamdunkelsb2486562003-04-11 20:22:03 +00001466 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001467 do_redraw_all(1, height);
1468 }
adamdunkelsb2486562003-04-11 20:22:03 +00001469 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001470#endif /* CTK_CONF_WINDOWMOVE */
1471 }
adamdunkelsb2486562003-04-11 20:22:03 +00001472
1473 if(redraw & REDRAW_ALL) {
1474 do_redraw_all(1, height);
1475#if CTK_CONF_MENUS
1476 } else if(redraw & REDRAW_MENUPART) {
1477 do_redraw_all(1, maxnitems + 1);
1478 } else if(redraw & REDRAW_MENUS) {
1479 ctk_draw_menus(&menus);
1480#endif /* CTK_CONF_MENUS */
1481 } else if(redraw & REDRAW_FOCUS) {
1482 if(dialog != NULL) {
1483 ctk_window_redraw(dialog);
1484 } else if(windows != NULL) {
1485 ctk_window_redraw(windows);
1486 } else {
1487 ctk_window_redraw(&desktop_window);
1488 }
1489 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001490 widgetptr = redraw_widgets;
1491 /* for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkelsb2486562003-04-11 20:22:03 +00001492 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001493 }*/
1494 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1495 ctk_widget_redraw(*widgetptr);
1496 *widgetptr = NULL;
1497 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001498 }
1499 }
1500 redraw = 0;
1501 redraw_widgetptr = 0;
1502
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001503}
1504/*-----------------------------------------------------------------------------------*/
adamdunkelscf90b0d2003-08-09 13:34:16 +00001505#if 0
adamdunkels78c03dc2003-04-09 13:45:05 +00001506static
1507DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001508{
adamdunkels78c03dc2003-04-09 13:45:05 +00001509 DISPATCHER_SIGHANDLER_ARGS(s, data);
1510
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001511 if(s == ctk_signal_timer) {
1512 if(mode == CTK_MODE_NORMAL) {
1513 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001514 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001515#if CTK_CONF_SCREENSAVER
1516 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1517 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001518#ifdef CTK_SCREENSAVER_INIT
1519 CTK_SCREENSAVER_INIT();
1520#endif /* CTK_SCREENSAVER_INIT */
1521 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001522#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001523 screensaver_timer = 0;
1524 }
1525 }
1526 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1527 }
1528}
adamdunkelscf90b0d2003-08-09 13:34:16 +00001529#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001530/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001531