blob: 68e9eabaf16dbad351e54e25be6f28b005d380ce [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 *
adamdunkelsb2486562003-04-11 20:22:03 +000035 * $Id: ctk.c,v 1.12 2003/04/11 20:22:03 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
47static unsigned char height, width;
48
49static unsigned char mode;
50
51static struct ctk_window desktop_window;
52static struct ctk_window *windows;
53static struct ctk_window *dialog;
54
55#if CTK_CONF_MENUS
56static struct ctk_menus menus;
57static struct ctk_menu *lastmenu;
58static struct ctk_menu desktopmenu;
59#endif /* CTK_CONF_MENUS */
60
61#ifndef NULL
62#define NULL (void *)0
63#endif /* NULL */
64
65
66#define REDRAW_NONE 0
67#define REDRAW_ALL 1
68#define REDRAW_FOCUS 2
69#define REDRAW_WIDGETS 4
70#define REDRAW_MENUS 8
71#define REDRAW_MENUPART 16
72
73#define MAX_REDRAWWIDGETS 4
74static unsigned char redraw;
75static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
76static unsigned char redraw_widgetptr;
77static unsigned char maxnitems;
78
79static unsigned char iconx, icony;
80#define ICONX_START (width - 5)
81#define ICONY_START 0
82#define ICONX_DELTA -8
83#define ICONY_DELTA 5
84#define ICONY_MAX (height - 4)
85
adamdunkelsc4902862003-04-09 00:30:45 +000086static void ctk_idle(void);
adamdunkels78c03dc2003-04-09 13:45:05 +000087static DISPATCHER_SIGHANDLER(ctk_sighandler, s, data);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000088static struct dispatcher_proc p =
adamdunkelsc4902862003-04-09 00:30:45 +000089 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, ctk_sighandler, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000090static ek_id_t ctkid;
91
adamdunkelsca9ddcb2003-03-19 14:13:31 +000092ek_signal_t ctk_signal_keypress,
93 ctk_signal_timer,
94 ctk_signal_button_activate,
95 ctk_signal_button_hover,
96 ctk_signal_hyperlink_activate,
97 ctk_signal_hyperlink_hover,
98 ctk_signal_menu_activate,
adamdunkelsc4902862003-04-09 00:30:45 +000099 ctk_signal_window_close,
100 ctk_signal_pointer_move,
adamdunkelsb2486562003-04-11 20:22:03 +0000101 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000102
adamdunkels19a787c2003-04-09 09:22:24 +0000103#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000104unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000105#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000106
107static unsigned short screensaver_timer;
108#define SCREENSAVER_TIMEOUT (5*60)
109
110#if CTK_CONF_MENUS
111/*-----------------------------------------------------------------------------------*/
112/* make_desktopmenu(void)
113 *
114 * Creates the leftmost menu, "Desktop". Since the desktop menu
115 * contains the list of all open windows, this function will be called
116 * whenever a window is opened or closed.
117 */
118static void
119make_desktopmenu(void)
120{
121 struct ctk_window *w;
122
123 desktopmenu.nitems = 0;
124
125 if(windows == NULL) {
126 ctk_menuitem_add(&desktopmenu, "(No windows)");
127 } else {
128 for(w = windows; w != NULL; w = w->next) {
129 ctk_menuitem_add(&desktopmenu, w->title);
130 }
131 }
132}
133#endif /* CTK_CONF_MENUS */
134/*-----------------------------------------------------------------------------------*/
135/* ctk_init(void)
136 *
137 * Initializes CTK. Must be called before any other CTK function.
138 */
139void
140ctk_init(void)
141{
142 ctkid = dispatcher_start(&p);
143
144 windows = NULL;
145 dialog = NULL;
146
147#if CTK_CONF_MENUS
148 ctk_menu_new(&desktopmenu, "Desktop");
149 make_desktopmenu();
150 menus.menus = menus.desktopmenu = &desktopmenu;
151#endif /* CTK_CONF_MENUS */
152
adamdunkelsb2486562003-04-11 20:22:03 +0000153#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000154 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000155 ctk_mouse_show();
156#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000157
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000158 ctk_draw_init();
159
160 height = ctk_draw_height();
161 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000162
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000163 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000164
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000165 ctk_signal_keypress = dispatcher_sigalloc();
166 ctk_signal_timer = dispatcher_sigalloc();
167 ctk_signal_button_activate = dispatcher_sigalloc();
168 ctk_signal_button_hover = dispatcher_sigalloc();
169 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
170 ctk_signal_hyperlink_hover = dispatcher_sigalloc();
171 ctk_signal_menu_activate = dispatcher_sigalloc();
172 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000173
174 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000175 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000176
177 dispatcher_listen(ctk_signal_timer);
178 dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
179
180 mode = CTK_MODE_NORMAL;
181
182 iconx = ICONX_START;
183 icony = ICONY_START;
184
185}
186/*-----------------------------------------------------------------------------------*/
187/* void ctk_mode_set()
188 */
189void
190ctk_mode_set(unsigned char m) {
191 mode = m;
192}
193/*-----------------------------------------------------------------------------------*/
194unsigned char
195ctk_mode_get(void) {
196 return mode;
197}
198/*-----------------------------------------------------------------------------------*/
199void
adamdunkelsd07a5422003-04-05 12:22:35 +0000200ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000201 ek_id_t id)
202{
203#if CTK_CONF_ICONS
204 icon->x = iconx;
205 icon->y = icony;
206 icon->widget.icon.owner = id;
207
208 icony += ICONY_DELTA;
209 if(icony >= ICONY_MAX) {
210 icony = ICONY_START;
211 iconx += ICONX_DELTA;
212 }
213
214 ctk_widget_add(&desktop_window, icon);
215#endif /* CTK_CONF_ICONS */
216}
217/*-----------------------------------------------------------------------------------*/
218void
219ctk_dialog_open(struct ctk_window *d)
220{
221 dialog = d;
222}
223/*-----------------------------------------------------------------------------------*/
224void
225ctk_dialog_close(void)
226{
227 dialog = NULL;
228}
229/*-----------------------------------------------------------------------------------*/
230void
adamdunkelsd07a5422003-04-05 12:22:35 +0000231ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000232{
233 struct ctk_window *w2;
234
235 /* Check if already open. */
236 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
237 if(w2 == NULL) {
238 /* Not open, so we add it at the head of the list of open
239 windows. */
240 w->next = windows;
241 if(windows != NULL) {
242 windows->prev = w;
243 }
244 windows = w;
245 w->prev = NULL;
246 } else {
247 /* Window already open, so we move it to the front of the windows
248 list. */
249 if(w != windows) {
250 if(w->next != NULL) {
251 w->next->prev = w->prev;
252 }
253 if(w->prev != NULL) {
254 w->prev->next = w->next;
255 }
256 w->next = windows;
257 windows->prev = w;
258 windows = w;
259 w->prev = NULL;
260 }
261 }
262
263#if CTK_CONF_MENUS
264 /* Recreate the Desktop menu's window entries.*/
265 make_desktopmenu();
266#endif /* CTK_CONF_MENUS */
267}
268/*-----------------------------------------------------------------------------------*/
269void
270ctk_window_close(struct ctk_window *w)
271{
272 struct ctk_window *w2;
273
274 if(w == NULL) {
275 return;
276 }
277
278 /* Check if the window to be closed is the first window on the
279 list. */
280 if(w == windows) {
281 windows = w->next;
282 if(windows != NULL) {
283 windows->prev = NULL;
284 }
285 w->next = w->prev = NULL;
286 } else {
287 /* Otherwise we step through the list until we find the window
288 before the one to be closed. We then redirect its ->next
289 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000290 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
291
292 if(w2 == NULL) {
293 /* The window wasn't open, so there is nothing more for us to
294 do. */
295 return;
296 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000297
298 if(w->next != NULL) {
299 w->next->prev = w->prev;
300 }
301 w2->next = w->next;
302
303 w->next = w->prev = NULL;
304 }
305
306#if CTK_CONF_MENUS
307 /* Recreate the Desktop menu's window entries.*/
308 make_desktopmenu();
309#endif /* CTK_CONF_MENUS */
310}
311/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000312static void
313make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000314{
315#if CTK_CONF_WINDOWMOVE
316 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
317#else
318 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
319#endif /* CTK_CONF_WINDOWMOVE */
320 CTK_WIDGET_ADD(window, &window->titlebutton);
321
322
323#if CTK_CONF_WINDOWCLOSE
324 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
325#else
326 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
327#endif /* CTK_CONF_WINDOWCLOSE */
328 CTK_WIDGET_ADD(window, &window->closebutton);
329}
330/*-----------------------------------------------------------------------------------*/
331void
332ctk_window_clear(struct ctk_window *window)
333{
334 window->active = window->inactive = window->focused = NULL;
335
336 make_windowbuttons(window);
337}
338/*-----------------------------------------------------------------------------------*/
339void
340ctk_menu_add(struct ctk_menu *menu)
341{
342#if CTK_CONF_MENUS
343 struct ctk_menu *m;
344
345 if(lastmenu == NULL) {
346 lastmenu = menu;
347 }
348
349 for(m = menus.menus; m->next != NULL; m = m->next) {
350 if(m == menu) {
351 return;
352 }
353 }
354 m->next = menu;
355 menu->next = NULL;
356#endif /* CTK_CONF_MENUS */
357}
358/*-----------------------------------------------------------------------------------*/
359void
360ctk_menu_remove(struct ctk_menu *menu)
361{
362#if CTK_CONF_MENUS
363 struct ctk_menu *m;
364
365 for(m = menus.menus; m->next != NULL; m = m->next) {
366 if(m->next == menu) {
367 m->next = menu->next;
368 return;
369 }
370 }
371#endif /* CTK_CONF_MENUS */
372}
373/*-----------------------------------------------------------------------------------*/
374static void
375do_redraw_all(unsigned char clipy1, unsigned char clipy2)
376{
377 struct ctk_window *w;
378 struct ctk_widget *widget;
379
380 if(mode != CTK_MODE_NORMAL &&
381 mode != CTK_MODE_WINDOWMOVE) {
382 return;
383 }
384
385 ctk_draw_clear(clipy1, clipy2);
386
387 /* Draw widgets in root window */
388 for(widget = desktop_window.active;
389 widget != NULL; widget = widget->next) {
390 ctk_draw_widget(widget, 0, clipy1, clipy2);
391 }
392
393 /* Draw windows */
394 if(windows != NULL) {
395 /* Find the last window.*/
396 for(w = windows; w->next != NULL; w = w->next);
397
398 /* Draw the windows from back to front. */
399 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000400 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000401 ctk_draw_window(w, 0, clipy1, clipy2);
402 }
403 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000404 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000405 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
406 }
407
408 /* Draw dialog (if any) */
409 if(dialog != NULL) {
410 ctk_draw_dialog(dialog);
411 }
412
413#if CTK_CONF_MENUS
414 ctk_draw_menus(&menus);
415#endif /* CTK_CONF_MENUS */
416}
417/*-----------------------------------------------------------------------------------*/
418void
419ctk_redraw(void)
420{
421 if(DISPATCHER_CURRENT() == ctkid) {
422 if(mode == CTK_MODE_NORMAL ||
423 mode == CTK_MODE_WINDOWMOVE) {
424 do_redraw_all(1, height);
425 }
426 } else {
427 redraw |= REDRAW_ALL;
428 }
429}
430/*-----------------------------------------------------------------------------------*/
431void
432ctk_window_redraw(struct ctk_window *w)
433{
434 /* Only redraw the window if it is a dialog or if it is the foremost
435 window. */
436 if(mode != CTK_MODE_NORMAL) {
437 return;
438 }
439
440 if(w == dialog) {
441 ctk_draw_dialog(w);
442 } else if(dialog == NULL &&
443#if CTK_CONF_MENUS
444 menus.open == NULL &&
445#endif /* CTK_CONF_MENUS */
446 windows == w) {
447 ctk_draw_window(w, CTK_FOCUS_WINDOW,
448 0, height);
449 }
450}
451/*-----------------------------------------------------------------------------------*/
452static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000453window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000454 unsigned char w, unsigned char h,
455 char *title)
456{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000457
458 if(w >= width - 2) {
459 window->x = 0;
460 } else {
461 window->x = (width - w - 2) / 2;
462 }
463 if(h >= height - 3) {
464 window->y = 0;
465 } else {
466 window->y = (height - h - 1) / 2;
467 }
468
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000469 window->w = w;
470 window->h = h;
471 window->title = title;
472 if(title != NULL) {
473 window->titlelen = strlen(title);
474 } else {
475 window->titlelen = 0;
476 }
477 window->next = window->prev = NULL;
478 window->owner = DISPATCHER_CURRENT();
479 window->active = window->inactive = window->focused = NULL;
480}
481/*-----------------------------------------------------------------------------------*/
482void
483ctk_window_new(struct ctk_window *window,
484 unsigned char w, unsigned char h,
485 char *title)
486{
487 window_new(window, w, h, title);
488
489 make_windowbuttons(window);
490}
491/*-----------------------------------------------------------------------------------*/
492void
adamdunkelsd07a5422003-04-05 12:22:35 +0000493ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000494 unsigned char w, unsigned char h)
495{
496 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000497}
498/*-----------------------------------------------------------------------------------*/
499void
adamdunkelsd07a5422003-04-05 12:22:35 +0000500ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000501 char *title)
502{
503#if CTK_CONF_MENUS
504 menu->next = NULL;
505 menu->title = title;
506 menu->titlelen = strlen(title);
507 menu->active = 0;
508 menu->nitems = 0;
509#endif /* CTK_CONF_MENUS */
510}
511/*-----------------------------------------------------------------------------------*/
512unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000513ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000514 char *name)
515{
516#if CTK_CONF_MENUS
517 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
518 return 0;
519 }
520 menu->items[menu->nitems].title = name;
521 menu->items[menu->nitems].titlelen = strlen(name);
522 return menu->nitems++;
523#else
524 return 0;
525#endif /* CTK_CONF_MENUS */
526}
527/*-----------------------------------------------------------------------------------*/
528static void
529add_redrawwidget(struct ctk_widget *w)
530{
531 static unsigned char i;
532
533 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
534 redraw |= REDRAW_FOCUS;
535 } else {
536 redraw |= REDRAW_WIDGETS;
537 /* Check if it is in the queue already. If so, we don't add it
538 again. */
539 for(i = 0; i < redraw_widgetptr; ++i) {
540 if(redraw_widgets[i] == w) {
541 return;
542 }
543 }
544 redraw_widgets[redraw_widgetptr++] = w;
545 }
546}
547/*-----------------------------------------------------------------------------------*/
548void
549ctk_widget_redraw(struct ctk_widget *widget)
550{
551 struct ctk_window *window;
552
553 if(mode != CTK_MODE_NORMAL) {
554 return;
555 }
556
557 /* If this function isn't called by CTK itself, we only queue the
558 redraw request. */
559 if(DISPATCHER_CURRENT() != ctkid) {
560 redraw |= REDRAW_WIDGETS;
561 add_redrawwidget(widget);
562 } else {
563
564 /* Only redraw widgets that are in the foremost window. If we
565 would allow redrawing widgets in non-focused windows, we would
566 have to redraw all the windows that cover the non-focused
567 window as well, which would lead to flickering.
568
569 Also, we avoid drawing any widgets when the menus are active.
570 */
571
572#if CTK_CONF_MENUS
573 if(menus.open == NULL)
574#endif /* CTK_CONF_MENUS */
575 {
576 window = widget->window;
577 if(window == dialog) {
578 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
579 } else if(window == windows) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000580 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000581 } else if(window == &desktop_window) {
582 ctk_draw_widget(widget, 0, 0, height);
583 }
584 }
585 }
586}
587/*-----------------------------------------------------------------------------------*/
588void
adamdunkelsd07a5422003-04-05 12:22:35 +0000589ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
590 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000591{
592 if(widget->type == CTK_WIDGET_LABEL ||
593 widget->type == CTK_WIDGET_SEPARATOR) {
594 widget->next = window->inactive;
595 window->inactive = widget;
596 widget->window = window;
597 } else {
598 widget->next = window->active;
599 window->active = widget;
600 widget->window = window;
601 if(window->focused == NULL) {
602 window->focused = widget;
603 }
604 }
605}
606/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000607static void
adamdunkelsb2486562003-04-11 20:22:03 +0000608select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000609{
610 struct ctk_window *window;
611
612 window = focus->window;
613
614 if(focus != window->focused) {
615 window->focused = focus;
616 /* The operation changed the focus, so we emit a "hover" signal
617 for those widgets that support it. */
618
619 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
620 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
621 window->owner);
622 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
623 dispatcher_emit(ctk_signal_button_hover, window->focused,
624 window->owner);
625 }
626
627 add_redrawwidget(window->focused);
628 }
629
630}
631/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000632#define UP 0
633#define DOWN 1
634#define LEFT 2
635#define RIGHT 3
636static void
637switch_focus_widget(unsigned char direction)
638{
639 register struct ctk_window *window;
640 register struct ctk_widget *focus;
641 struct ctk_widget *widget;
642
643
644 if(dialog != NULL) {
645 window = dialog;
646 } else {
647 window = windows;
648 }
649
650 /* If there are no windows open, we move focus around between the
651 icons on the root window instead. */
652 if(window == NULL) {
653 window = &desktop_window;
654 }
655
656 focus = window->focused;
657 add_redrawwidget(focus);
658
659 if((direction & 1) == 0) {
660 /* Move focus "up" */
661 focus = focus->next;
662 } else {
663 /* Move focus "down" */
664 for(widget = window->active;
665 widget != NULL; widget = widget->next) {
666 if(widget->next == focus) {
667 break;
668 }
669 }
670 focus = widget;
671 if(focus == NULL) {
672 if(window->active != NULL) {
673 for(focus = window->active;
674 focus->next != NULL; focus = focus->next);
675 }
676 }
677 }
678 if(focus == NULL) {
679 focus = window->active;
680 }
adamdunkelse0683312003-04-09 09:02:52 +0000681
adamdunkelsb2486562003-04-11 20:22:03 +0000682 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000683}
684/*-----------------------------------------------------------------------------------*/
685#if CTK_CONF_MENUS
686static void
687switch_open_menu(unsigned char rightleft)
688{
689 struct ctk_menu *menu;
690
691 if(rightleft == 0) {
692 /* Move right */
693 for(menu = menus.menus; menu != NULL; menu = menu->next) {
694 if(menu->next == menus.open) {
695 break;
696 }
697 }
698 lastmenu = menus.open;
699 menus.open = menu;
700 if(menus.open == NULL) {
701 for(menu = menus.menus;
702 menu->next != NULL; menu = menu->next);
703 menus.open = menu;
704 }
705 } else {
706 /* Move to left */
707 lastmenu = menus.open;
708 menus.open = menus.open->next;
709 if(menus.open == NULL) {
710 menus.open = menus.menus;
711 }
712 }
713
714 menus.open->active = 0;
715 /* ctk_redraw();*/
716}
717/*-----------------------------------------------------------------------------------*/
718static void
719switch_menu_item(unsigned char updown)
720{
721 register struct ctk_menu *m;
722
723 m = menus.open;
724
725 if(updown == 0) {
726 /* Move up */
727 if(m->active == 0) {
728 m->active = m->nitems - 1;
729 } else {
730 --m->active;
731 if(m->items[m->active].title[0] == '-') {
732 --m->active;
733 }
734 }
735 } else {
736 /* Move down */
737 if(m->active >= m->nitems - 1) {
738 m->active = 0;
739 } else {
740 ++m->active;
741 if(m->items[m->active].title[0] == '-') {
742 ++m->active;
743 }
744 }
745 }
746
747}
748#endif /* CTK_CONF_MENUS */
749/*-----------------------------------------------------------------------------------*/
750static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000751activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000752{
753 static unsigned char len;
754
755 if(w->type == CTK_WIDGET_BUTTON) {
756 if(w == (struct ctk_widget *)&windows->closebutton) {
757#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000758 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000759 ctk_window_close(windows);
760 return REDRAW_ALL;
761#endif /* CTK_CONF_WINDOWCLOSE */
762 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
763#if CTK_CONF_WINDOWCLOSE
764 mode = CTK_MODE_WINDOWMOVE;
765#endif /* CTK_CONF_WINDOWCLOSE */
766 } else {
767 dispatcher_emit(ctk_signal_button_activate, w,
768 w->window->owner);
769 }
770#if CTK_CONF_ICONS
771 } else if(w->type == CTK_WIDGET_ICON) {
772 dispatcher_emit(ctk_signal_button_activate, w,
773 w->widget.icon.owner);
774#endif /* CTK_CONF_ICONS */
775 } else if(w->type == CTK_WIDGET_HYPERLINK) {
776 dispatcher_emit(ctk_signal_hyperlink_activate, w,
777 DISPATCHER_BROADCAST);
778 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
779 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
780 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
781 len = strlen(w->widget.textentry.text);
782 if(w->widget.textentry.xpos > len) {
783 w->widget.textentry.xpos = len;
784 }
785 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
786 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
787 }
788 add_redrawwidget(w);
789 return REDRAW_WIDGETS;
790 }
791 return REDRAW_NONE;
792}
793/*-----------------------------------------------------------------------------------*/
794static void
795textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000796 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000797{
798 static char *cptr, *cptr2;
799 static unsigned char len, txpos, typos, tlen;
800
801 txpos = t->xpos;
802 typos = t->ypos;
803 tlen = t->len;
804
805 cptr = &t->text[txpos + typos * tlen];
806
807 switch(c) {
808 case CH_CURS_LEFT:
809 if(txpos > 0) {
810 --txpos;
811 }
812 break;
813
814 case CH_CURS_RIGHT:
815 if(txpos < tlen &&
816 *cptr != 0) {
817 ++txpos;
818 }
819 break;
820
821 case CH_CURS_UP:
822#if CTK_CONF_TEXTENTRY_MULTILINE
823 if(t->h == 1) {
824 txpos = 0;
825 } else {
826 if(typos > 0) {
827 --typos;
828 } else {
829 t->state = CTK_TEXTENTRY_NORMAL;
830 }
831 }
832#else
833 txpos = 0;
834#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
835 break;
836
837 case CH_CURS_DOWN:
838#if CTK_CONF_TEXTENTRY_MULTILINE
839 if(t->h == 1) {
840 txpos = strlen(t->text);
841 } else {
842 if(typos < t->h - 1) {
843 ++typos;
844 } else {
845 t->state = CTK_TEXTENTRY_NORMAL;
846 }
847 }
848#else
849 txpos = strlen(t->text);
850#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
851 break;
852
853 case CH_ENTER:
854#if CTK_CONF_TEXTENTRY_MULTILINE
855 if(t->h == 1) {
856 t->state = CTK_TEXTENTRY_NORMAL;
857 } else {
858 if(typos < t->h - 1) {
859 ++typos;
860 txpos = 0;
861 } else {
862 t->state = CTK_TEXTENTRY_NORMAL;
863 }
864 }
865#else
866 t->state = CTK_TEXTENTRY_NORMAL;
867#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
868 break;
869
870 default:
871 len = tlen - txpos - 1;
872 if(c == CH_DEL) {
873 if(txpos > 0 && len > 0) {
874 strncpy(cptr - 1, cptr,
875 len);
876 *(cptr + len - 1) = 0;
877 --txpos;
878 }
879 } else {
880 if(len > 0) {
881 cptr2 = cptr + len - 1;
882 while(cptr2 + 1 > cptr) {
883 *(cptr2 + 1) = *cptr2;
884 --cptr2;
885 }
886
887 *cptr = c;
888 ++txpos;
889 }
890 }
891 break;
892 }
893
894 t->xpos = txpos;
895 t->ypos = typos;
896}
897/*-----------------------------------------------------------------------------------*/
898#if CTK_CONF_MENUS
899static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000900activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000901{
902 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000903
904 lastmenu = menus.open;
905 if(menus.open == &desktopmenu) {
906 for(w = windows; w != NULL; w = w->next) {
907 if(w->title == desktopmenu.items[desktopmenu.active].title) {
908 ctk_window_open(w);
909 menus.open = NULL;
910 return REDRAW_ALL;
911 }
912 }
913 } else {
914 dispatcher_emit(ctk_signal_menu_activate, menus.open,
915 DISPATCHER_BROADCAST);
916 }
917 menus.open = NULL;
918 return REDRAW_MENUPART;
919}
920/*-----------------------------------------------------------------------------------*/
921static unsigned char
922menus_input(ctk_arch_key_t c)
923{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000924
925 if(menus.open->nitems > maxnitems) {
926 maxnitems = menus.open->nitems;
927 }
928
929
930 switch(c) {
931 case CH_CURS_RIGHT:
932 switch_open_menu(1);
933
934 return REDRAW_MENUPART;
935
936 case CH_CURS_DOWN:
937 switch_menu_item(1);
938 return REDRAW_MENUS;
939
940 case CH_CURS_LEFT:
941 switch_open_menu(0);
942 return REDRAW_MENUPART;
943
944 case CH_CURS_UP:
945 switch_menu_item(0);
946 return REDRAW_MENUS;
947
948 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000949 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000950
adamdunkels88ed9c42003-03-28 12:10:09 +0000951 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000952 lastmenu = menus.open;
953 menus.open = NULL;
954 return REDRAW_MENUPART;
955 }
adamdunkelsb2486562003-04-11 20:22:03 +0000956
957 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958}
959#endif /* CTK_CONF_MENUS */
960/*-----------------------------------------------------------------------------------*/
961static void
adamdunkelsc4902862003-04-09 00:30:45 +0000962ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000963{
964 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +0000965 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000966 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +0000967 register struct ctk_widget *widget;
968#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000969 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
970 mouse_clicked;
971 static unsigned char menux;
972 struct ctk_menu *menu;
973
adamdunkels19a787c2003-04-09 09:22:24 +0000974#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000975
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000976#if CTK_CONF_MENUS
977 if(menus.open != NULL) {
978 maxnitems = menus.open->nitems;
979 } else {
980 maxnitems = 0;
981 }
982#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +0000983
984#if CTK_CONF_MOUSE_SUPPORT
985 mouse_button_changed = mouse_moved = mouse_clicked = 0;
986
987 /* See if there is any change in the buttons. */
988 if(ctk_mouse_button() != mouse_button) {
989 mouse_button = ctk_mouse_button();
990 mouse_button_changed = 1;
991 if(mouse_button == 0) {
992 mouse_clicked = 1;
993 }
994 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000995
adamdunkelsb2486562003-04-11 20:22:03 +0000996 /* Check if the mouse pointer has moved. */
997 if(ctk_mouse_x() != mouse_x ||
998 ctk_mouse_y() != mouse_y) {
999 mouse_x = ctk_mouse_x();
1000 mouse_y = ctk_mouse_y();
1001 mouse_moved = 1;
1002 }
1003
1004 mxc = ctk_mouse_xtoc(mouse_x);
1005 myc = ctk_mouse_ytoc(mouse_y);
1006#endif /* CTK_CONF_MOUSE_SUPPORT */
1007
1008
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009 if(mode == CTK_MODE_SCREENSAVER) {
1010#ifdef CTK_SCREENSAVER_RUN
1011 CTK_SCREENSAVER_RUN();
1012#endif /* CTK_SCREENSAVER_RUN */
adamdunkelsb2486562003-04-11 20:22:03 +00001013 if(ctk_arch_keyavail()
1014#if CTK_CONF_MOUSE_SUPPORT
1015 || mouse_moved || mouse_button_changed
1016#endif /* CTK_CONF_MOUSE_SUPPORT */
1017 ) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001018 mode = CTK_MODE_NORMAL;
1019 ctk_draw_init();
1020 ctk_redraw();
1021 }
adamdunkelsc4902862003-04-09 00:30:45 +00001022 } else if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001023#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001024 /* If there is any change in the mouse conditions, find out in
1025 which window the mouse pointer currently is in order to send
1026 the correct signals, or bring a window to focus. */
1027 if(mouse_moved || mouse_button_changed) {
1028 ctk_mouse_show();
1029 screensaver_timer = 0;
1030
1031 if(myc == 0) {
1032 /* Here we should do whatever needs to be done when the mouse
1033 moves around and clicks in the menubar. */
1034 if(mouse_clicked) {
1035 /* Find out which menu that the mouse pointer is in. Start
1036 with the ->next menu after the desktop menu. We assume
1037 that the menus start one character from the left screen
1038 side and that the desktop menu is farthest to the
1039 right. */
1040 menux = 1;
1041 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1042 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1043 break;
adamdunkelse0683312003-04-09 09:02:52 +00001044 }
adamdunkelsb2486562003-04-11 20:22:03 +00001045 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001046 }
adamdunkelsb2486562003-04-11 20:22:03 +00001047
1048 /* Also check desktop menu. */
1049 if(mxc >= width - 7 &&
1050 mxc <= width - 1) {
1051 menu = &desktopmenu;
1052 }
1053
1054 menus.open = menu;
1055 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001056 }
adamdunkelse0683312003-04-09 09:02:52 +00001057 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001058 --myc;
1059
1060 if(menus.open != NULL) {
1061 /* Do whatever needs to be done when a menu is open. */
1062
1063 if(menus.open == &desktopmenu) {
1064 menux = width - CTK_CONF_MENUWIDTH;
1065 } else {
1066 menux = 1;
1067 for(menu = menus.menus->next; menu != menus.open;
1068 menu = menu->next) {
1069 menux += menu->titlelen;
1070 }
1071 }
1072
1073 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1074 menus.open->active = myc;
1075 }
1076
1077 if(mouse_clicked) {
1078 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1079 redraw |= activate_menu();
1080 } else {
1081 lastmenu = menus.open;
1082 menus.open = NULL;
1083 redraw |= REDRAW_MENUPART;
1084 }
1085 } else {
1086 redraw |= REDRAW_MENUS;
1087 }
1088 } else {
1089
1090 /* Walk through the windows from top to bottom to see in which
1091 window the mouse pointer is. */
1092 if(dialog != NULL) {
1093 window = dialog;
1094 } else {
1095 for(window = windows; window != NULL; window = window->next) {
1096 /* Check if the mouse is within the window. */
1097 if(mxc >= window->x &&
1098 mxc <= window->x + window->w &&
1099 myc >= window->y &&
1100 myc <= window->y + window->h) {
1101 break;
1102 }
1103 }
1104 }
1105
1106
1107 /* If we didn't find any window, and there are no windows
1108 open, the mouse pointer will definately be within the
1109 background desktop window. */
1110 if(window == NULL &&
1111 windows == NULL) {
1112 window = &desktop_window;
1113 }
1114
1115 /* If the mouse pointer moves around outside of the currently
1116 focused window (or dialog), we should not have any focused
1117 widgets in the focused window so we make sure that there
1118 are none. */
1119 if(windows != NULL &&
1120 window != windows &&
1121 windows->focused != NULL){
1122 add_redrawwidget(windows->focused);
1123 windows->focused = NULL;
1124 redraw |= REDRAW_WIDGETS;
1125 }
1126
1127 if(window != NULL) {
1128 /* If the mouse was clicked outside of the current window, we
1129 bring the clicked window to front. */
1130 if(dialog == NULL &&
1131 window != &desktop_window &&
1132 window != windows &&
1133 mouse_clicked) {
1134 /* Bring window to front. */
1135 ctk_window_open(window);
1136 redraw |= REDRAW_ALL;
1137 } else {
1138
1139 /* Find out which widget currently is under the mouse pointer
1140 and give it focus, unless it already has focus. */
1141 mxc = mxc - window->x - 1;
1142 myc = myc - window->y - 1;
1143
1144 /* See if the mouse pointer is on a widget. If so, it should be
1145 selected and, if the button is clicked, activated. */
1146 for(widget = window->active; widget != NULL;
1147 widget = widget->next) {
1148 if(mxc >= widget->x &&
1149 mxc <= widget->x + widget->w &&
1150 (myc == widget->y ||
1151 ((widget->type == CTK_WIDGET_BITMAP ||
1152 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1153 widget->type == CTK_WIDGET_ICON) &&
1154 (myc >= widget->y &&
1155 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1156 break;
1157 }
1158 }
1159
1160
1161 if(mouse_moved) {
1162 dispatcher_emit(ctk_signal_pointer_move, NULL,
1163 window->owner);
1164
1165
1166
1167 if(window->focused != NULL &&
1168 widget != window->focused) {
1169 add_redrawwidget(window->focused);
1170 if(CTK_WIDGET_TYPE(window->focused) ==
1171 CTK_WIDGET_TEXTENTRY) {
1172 ((struct ctk_textentry *)(window->focused))->state =
1173 CTK_TEXTENTRY_NORMAL;
1174 }
1175 window->focused = NULL;
1176 }
1177 redraw |= REDRAW_WIDGETS;
1178 if(widget != NULL) {
1179 select_widget(widget);
1180 }
1181 }
1182
1183 if(mouse_button_changed) {
1184 dispatcher_emit(ctk_signal_pointer_button,
1185 (ek_data_t)mouse_button,
1186 window->owner);
1187 if(mouse_clicked && widget != NULL) {
1188 select_widget(widget);
1189 redraw |= activate(widget);
1190 }
1191 }
1192 }
1193 }
1194 }
adamdunkelsc4902862003-04-09 00:30:45 +00001195 }
1196 }
adamdunkels19a787c2003-04-09 09:22:24 +00001197#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001198
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001199 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001200
1201 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001202
1203 screensaver_timer = 0;
1204
adamdunkelsb2486562003-04-11 20:22:03 +00001205 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001206
1207 if(dialog != NULL) {
1208 window = dialog;
1209 } else if(windows != NULL) {
1210 window = windows;
1211 } else {
1212 window = &desktop_window;
1213 }
1214 widget = window->focused;
1215
1216
1217 if(widget != NULL &&
1218 widget->type == CTK_WIDGET_TEXTENTRY &&
1219 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1220 textentry_input(c, (struct ctk_textentry *)widget);
1221 add_redrawwidget(widget);
1222#if CTK_CONF_MENUS
1223 } else if(menus.open != NULL) {
1224 redraw |= menus_input(c);
1225#endif /* CTK_CONF_MENUS */
1226 } else {
1227 switch(c) {
1228 case CH_CURS_RIGHT:
1229 switch_focus_widget(RIGHT);
1230 break;
1231 case CH_CURS_DOWN:
1232 switch_focus_widget(DOWN);
1233 break;
1234 case CH_CURS_LEFT:
1235 switch_focus_widget(LEFT);
1236 break;
1237 case CH_CURS_UP:
1238 switch_focus_widget(UP);
1239 break;
1240 case CH_ENTER:
1241 redraw |= activate(widget);
1242 break;
1243#if CTK_CONF_MENUS
1244 case CTK_CONF_MENU_KEY:
1245 if(dialog == NULL) {
1246 if(lastmenu == NULL) {
1247 menus.open = menus.menus;
1248 } else {
1249 menus.open = lastmenu;
1250 }
1251 menus.open->active = 0;
1252 redraw |= REDRAW_MENUS;
1253 }
1254 break;
1255#endif /* CTK_CONF_MENUS */
1256 case CTK_CONF_WINDOWSWITCH_KEY:
1257 if(windows != NULL) {
1258 for(window = windows; window->next != NULL;
1259 window = window->next);
1260 ctk_window_open(window);
1261 ctk_redraw();
1262 }
1263 break;
1264 default:
1265 if(widget->type == CTK_WIDGET_TEXTENTRY) {
1266 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1267 textentry_input(c, (struct ctk_textentry *)widget);
1268 add_redrawwidget(widget);
1269 } else {
1270 dispatcher_emit(ctk_signal_keypress, (void *)c,
1271 window->owner);
1272 }
1273 break;
1274 }
1275 }
1276
1277 if(redraw & REDRAW_WIDGETS) {
1278 for(i = 0; i < redraw_widgetptr; ++i) {
1279 ctk_widget_redraw(redraw_widgets[i]);
1280 }
1281 redraw &= ~REDRAW_WIDGETS;
1282 redraw_widgetptr = 0;
1283 }
1284 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001285#if CTK_CONF_WINDOWMOVE
1286 } else if(mode == CTK_MODE_WINDOWMOVE) {
1287
1288 redraw = 0;
1289
1290 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001291
1292#if CTK_CONF_MOUSE_SUPPORT
1293
1294 /* If the mouse has moved, we move the window as well. */
1295 if(mouse_moved) {
1296
1297 if(window->w + mxc + 2 >= width) {
1298 window->x = width - 2 - window->w;
1299 } else {
1300 window->x = mxc;
1301 }
1302
1303 if(window->h + myc + 2 >= height) {
1304 window->y = height - 2 - window->h;
1305 } else {
1306 window->y = myc;
1307 }
1308 if(window->y > 0) {
1309 --window->y;
1310 }
1311
1312 redraw = REDRAW_ALL;
1313 }
1314
1315 /* Check if the mouse has been clicked, and stop moving the window
1316 if so. */
1317 if(mouse_button_changed &&
1318 mouse_button == 0) {
1319 mode = CTK_MODE_NORMAL;
1320 redraw = REDRAW_ALL;
1321 }
1322#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001323
1324 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1325
1326 screensaver_timer = 0;
1327
1328 c = ctk_arch_getkey();
1329
1330 switch(c) {
1331 case CH_CURS_RIGHT:
1332 ++window->x;
1333 if(window->x + window->w + 1 >= width) {
1334 --window->x;
1335 }
1336 redraw = REDRAW_ALL;
1337 break;
1338 case CH_CURS_LEFT:
1339 if(window->x > 0) {
1340 --window->x;
1341 }
1342 redraw = REDRAW_ALL;
1343 break;
1344 case CH_CURS_DOWN:
1345 ++window->y;
1346 if(window->y + window->h + 2 >= height) {
1347 --window->y;
1348 }
1349 redraw = REDRAW_ALL;
1350 break;
1351 case CH_CURS_UP:
1352 if(window->y > 0) {
1353 --window->y;
1354 }
1355 redraw = REDRAW_ALL;
1356 break;
1357 case CH_ENTER:
1358 case CH_ESC:
1359 mode = CTK_MODE_NORMAL;
1360 redraw = REDRAW_ALL;
1361 break;
1362 }
1363 }
adamdunkelsb2486562003-04-11 20:22:03 +00001364 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365 do_redraw_all(1, height);
1366 }
adamdunkelsb2486562003-04-11 20:22:03 +00001367 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001368#endif /* CTK_CONF_WINDOWMOVE */
1369 }
adamdunkelsb2486562003-04-11 20:22:03 +00001370
1371 if(redraw & REDRAW_ALL) {
1372 do_redraw_all(1, height);
1373#if CTK_CONF_MENUS
1374 } else if(redraw & REDRAW_MENUPART) {
1375 do_redraw_all(1, maxnitems + 1);
1376 } else if(redraw & REDRAW_MENUS) {
1377 ctk_draw_menus(&menus);
1378#endif /* CTK_CONF_MENUS */
1379 } else if(redraw & REDRAW_FOCUS) {
1380 if(dialog != NULL) {
1381 ctk_window_redraw(dialog);
1382 } else if(windows != NULL) {
1383 ctk_window_redraw(windows);
1384 } else {
1385 ctk_window_redraw(&desktop_window);
1386 }
1387 } else if(redraw & REDRAW_WIDGETS) {
1388 for(i = 0; i < redraw_widgetptr; ++i) {
1389 ctk_widget_redraw(redraw_widgets[i]);
1390 }
1391 }
1392 redraw = 0;
1393 redraw_widgetptr = 0;
1394
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001395}
1396/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001397static
1398DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001399{
adamdunkels78c03dc2003-04-09 13:45:05 +00001400 DISPATCHER_SIGHANDLER_ARGS(s, data);
1401
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001402 if(s == ctk_signal_timer) {
1403 if(mode == CTK_MODE_NORMAL) {
1404 ++screensaver_timer;
1405 if(screensaver_timer == SCREENSAVER_TIMEOUT) {
1406#ifdef CTK_SCREENSAVER_INIT
1407 CTK_SCREENSAVER_INIT();
1408#endif /* CTK_SCREENSAVER_INIT */
1409 mode = CTK_MODE_SCREENSAVER;
1410 screensaver_timer = 0;
1411 }
1412 }
1413 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1414 }
1415}
1416/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001417