blob: 250057b0fa4e78f25f27e4b7d6ec4b333916cc09 [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 *
adamdunkels58917a82003-04-18 00:18:38 +000035 * $Id: ctk.c,v 1.15 2003/04/18 00:18:38 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,
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
adamdunkels19a787c2003-04-09 09:22:24 +0000105#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000106unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000107#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000108
109static unsigned short screensaver_timer;
110#define SCREENSAVER_TIMEOUT (5*60)
111
112#if CTK_CONF_MENUS
113/*-----------------------------------------------------------------------------------*/
114/* make_desktopmenu(void)
115 *
116 * Creates the leftmost menu, "Desktop". Since the desktop menu
117 * contains the list of all open windows, this function will be called
118 * whenever a window is opened or closed.
119 */
120static void
121make_desktopmenu(void)
122{
123 struct ctk_window *w;
124
125 desktopmenu.nitems = 0;
126
127 if(windows == NULL) {
128 ctk_menuitem_add(&desktopmenu, "(No windows)");
129 } else {
130 for(w = windows; w != NULL; w = w->next) {
131 ctk_menuitem_add(&desktopmenu, w->title);
132 }
133 }
134}
135#endif /* CTK_CONF_MENUS */
136/*-----------------------------------------------------------------------------------*/
137/* ctk_init(void)
138 *
139 * Initializes CTK. Must be called before any other CTK function.
140 */
141void
142ctk_init(void)
143{
144 ctkid = dispatcher_start(&p);
145
146 windows = NULL;
147 dialog = NULL;
148
149#if CTK_CONF_MENUS
150 ctk_menu_new(&desktopmenu, "Desktop");
151 make_desktopmenu();
152 menus.menus = menus.desktopmenu = &desktopmenu;
153#endif /* CTK_CONF_MENUS */
154
adamdunkelsb2486562003-04-11 20:22:03 +0000155#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000156 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000157 ctk_mouse_show();
158#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000159
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000160 ctk_draw_init();
161
162 height = ctk_draw_height();
163 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000164
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000165 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000166
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000167 ctk_signal_keypress = dispatcher_sigalloc();
168 ctk_signal_timer = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000169
170 ctk_signal_button_activate =
171 ctk_signal_widget_activate = dispatcher_sigalloc();
172
173 ctk_signal_button_hover =
174 ctk_signal_hyperlink_hover =
175 ctk_signal_widget_select = dispatcher_sigalloc();
176
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000177 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000178
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000179 ctk_signal_menu_activate = dispatcher_sigalloc();
180 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000181
182 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000183 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000184
185 dispatcher_listen(ctk_signal_timer);
186 dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
187
188 mode = CTK_MODE_NORMAL;
189
190 iconx = ICONX_START;
191 icony = ICONY_START;
192
193}
194/*-----------------------------------------------------------------------------------*/
195/* void ctk_mode_set()
196 */
197void
198ctk_mode_set(unsigned char m) {
199 mode = m;
200}
201/*-----------------------------------------------------------------------------------*/
202unsigned char
203ctk_mode_get(void) {
204 return mode;
205}
206/*-----------------------------------------------------------------------------------*/
207void
adamdunkelsd07a5422003-04-05 12:22:35 +0000208ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000209 ek_id_t id)
210{
211#if CTK_CONF_ICONS
212 icon->x = iconx;
213 icon->y = icony;
214 icon->widget.icon.owner = id;
215
216 icony += ICONY_DELTA;
217 if(icony >= ICONY_MAX) {
218 icony = ICONY_START;
219 iconx += ICONX_DELTA;
220 }
221
222 ctk_widget_add(&desktop_window, icon);
223#endif /* CTK_CONF_ICONS */
224}
225/*-----------------------------------------------------------------------------------*/
226void
227ctk_dialog_open(struct ctk_window *d)
228{
229 dialog = d;
230}
231/*-----------------------------------------------------------------------------------*/
232void
233ctk_dialog_close(void)
234{
235 dialog = NULL;
236}
237/*-----------------------------------------------------------------------------------*/
238void
adamdunkelsd07a5422003-04-05 12:22:35 +0000239ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000240{
241 struct ctk_window *w2;
242
243 /* Check if already open. */
244 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
245 if(w2 == NULL) {
246 /* Not open, so we add it at the head of the list of open
247 windows. */
248 w->next = windows;
249 if(windows != NULL) {
250 windows->prev = w;
251 }
252 windows = w;
253 w->prev = NULL;
254 } else {
255 /* Window already open, so we move it to the front of the windows
256 list. */
257 if(w != windows) {
258 if(w->next != NULL) {
259 w->next->prev = w->prev;
260 }
261 if(w->prev != NULL) {
262 w->prev->next = w->next;
263 }
264 w->next = windows;
265 windows->prev = w;
266 windows = w;
267 w->prev = NULL;
268 }
269 }
270
271#if CTK_CONF_MENUS
272 /* Recreate the Desktop menu's window entries.*/
273 make_desktopmenu();
274#endif /* CTK_CONF_MENUS */
275}
276/*-----------------------------------------------------------------------------------*/
277void
278ctk_window_close(struct ctk_window *w)
279{
280 struct ctk_window *w2;
281
282 if(w == NULL) {
283 return;
284 }
285
286 /* Check if the window to be closed is the first window on the
287 list. */
288 if(w == windows) {
289 windows = w->next;
290 if(windows != NULL) {
291 windows->prev = NULL;
292 }
293 w->next = w->prev = NULL;
294 } else {
295 /* Otherwise we step through the list until we find the window
296 before the one to be closed. We then redirect its ->next
297 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000298 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
299
300 if(w2 == NULL) {
301 /* The window wasn't open, so there is nothing more for us to
302 do. */
303 return;
304 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000305
306 if(w->next != NULL) {
307 w->next->prev = w->prev;
308 }
309 w2->next = w->next;
310
311 w->next = w->prev = NULL;
312 }
313
314#if CTK_CONF_MENUS
315 /* Recreate the Desktop menu's window entries.*/
316 make_desktopmenu();
317#endif /* CTK_CONF_MENUS */
318}
319/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000320static void
321make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322{
323#if CTK_CONF_WINDOWMOVE
324 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
325#else
326 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
327#endif /* CTK_CONF_WINDOWMOVE */
328 CTK_WIDGET_ADD(window, &window->titlebutton);
329
330
331#if CTK_CONF_WINDOWCLOSE
332 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
333#else
334 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
335#endif /* CTK_CONF_WINDOWCLOSE */
336 CTK_WIDGET_ADD(window, &window->closebutton);
337}
338/*-----------------------------------------------------------------------------------*/
339void
340ctk_window_clear(struct ctk_window *window)
341{
342 window->active = window->inactive = window->focused = NULL;
343
344 make_windowbuttons(window);
345}
346/*-----------------------------------------------------------------------------------*/
347void
348ctk_menu_add(struct ctk_menu *menu)
349{
350#if CTK_CONF_MENUS
351 struct ctk_menu *m;
352
353 if(lastmenu == NULL) {
354 lastmenu = menu;
355 }
356
357 for(m = menus.menus; m->next != NULL; m = m->next) {
358 if(m == menu) {
359 return;
360 }
361 }
362 m->next = menu;
363 menu->next = NULL;
364#endif /* CTK_CONF_MENUS */
365}
366/*-----------------------------------------------------------------------------------*/
367void
368ctk_menu_remove(struct ctk_menu *menu)
369{
370#if CTK_CONF_MENUS
371 struct ctk_menu *m;
372
373 for(m = menus.menus; m->next != NULL; m = m->next) {
374 if(m->next == menu) {
375 m->next = menu->next;
376 return;
377 }
378 }
379#endif /* CTK_CONF_MENUS */
380}
381/*-----------------------------------------------------------------------------------*/
382static void
383do_redraw_all(unsigned char clipy1, unsigned char clipy2)
384{
385 struct ctk_window *w;
386 struct ctk_widget *widget;
387
388 if(mode != CTK_MODE_NORMAL &&
389 mode != CTK_MODE_WINDOWMOVE) {
390 return;
391 }
392
393 ctk_draw_clear(clipy1, clipy2);
394
395 /* Draw widgets in root window */
396 for(widget = desktop_window.active;
397 widget != NULL; widget = widget->next) {
398 ctk_draw_widget(widget, 0, clipy1, clipy2);
399 }
400
401 /* Draw windows */
402 if(windows != NULL) {
403 /* Find the last window.*/
404 for(w = windows; w->next != NULL; w = w->next);
405
406 /* Draw the windows from back to front. */
407 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000408 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000409 ctk_draw_window(w, 0, clipy1, clipy2);
410 }
411 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000412 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000413 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
414 }
415
416 /* Draw dialog (if any) */
417 if(dialog != NULL) {
418 ctk_draw_dialog(dialog);
419 }
420
421#if CTK_CONF_MENUS
422 ctk_draw_menus(&menus);
423#endif /* CTK_CONF_MENUS */
424}
425/*-----------------------------------------------------------------------------------*/
426void
427ctk_redraw(void)
428{
429 if(DISPATCHER_CURRENT() == ctkid) {
430 if(mode == CTK_MODE_NORMAL ||
431 mode == CTK_MODE_WINDOWMOVE) {
432 do_redraw_all(1, height);
433 }
434 } else {
435 redraw |= REDRAW_ALL;
436 }
437}
438/*-----------------------------------------------------------------------------------*/
439void
440ctk_window_redraw(struct ctk_window *w)
441{
442 /* Only redraw the window if it is a dialog or if it is the foremost
443 window. */
444 if(mode != CTK_MODE_NORMAL) {
445 return;
446 }
447
448 if(w == dialog) {
449 ctk_draw_dialog(w);
450 } else if(dialog == NULL &&
451#if CTK_CONF_MENUS
452 menus.open == NULL &&
453#endif /* CTK_CONF_MENUS */
454 windows == w) {
455 ctk_draw_window(w, CTK_FOCUS_WINDOW,
456 0, height);
457 }
458}
459/*-----------------------------------------------------------------------------------*/
460static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000461window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000462 unsigned char w, unsigned char h,
463 char *title)
464{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000465
466 if(w >= width - 2) {
467 window->x = 0;
468 } else {
469 window->x = (width - w - 2) / 2;
470 }
471 if(h >= height - 3) {
472 window->y = 0;
473 } else {
474 window->y = (height - h - 1) / 2;
475 }
476
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000477 window->w = w;
478 window->h = h;
479 window->title = title;
480 if(title != NULL) {
481 window->titlelen = strlen(title);
482 } else {
483 window->titlelen = 0;
484 }
485 window->next = window->prev = NULL;
486 window->owner = DISPATCHER_CURRENT();
487 window->active = window->inactive = window->focused = NULL;
488}
489/*-----------------------------------------------------------------------------------*/
490void
491ctk_window_new(struct ctk_window *window,
492 unsigned char w, unsigned char h,
493 char *title)
494{
495 window_new(window, w, h, title);
496
497 make_windowbuttons(window);
498}
499/*-----------------------------------------------------------------------------------*/
500void
adamdunkelsd07a5422003-04-05 12:22:35 +0000501ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000502 unsigned char w, unsigned char h)
503{
504 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000505}
506/*-----------------------------------------------------------------------------------*/
507void
adamdunkelsd07a5422003-04-05 12:22:35 +0000508ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000509 char *title)
510{
511#if CTK_CONF_MENUS
512 menu->next = NULL;
513 menu->title = title;
514 menu->titlelen = strlen(title);
515 menu->active = 0;
516 menu->nitems = 0;
517#endif /* CTK_CONF_MENUS */
518}
519/*-----------------------------------------------------------------------------------*/
520unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000521ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000522 char *name)
523{
524#if CTK_CONF_MENUS
525 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
526 return 0;
527 }
528 menu->items[menu->nitems].title = name;
529 menu->items[menu->nitems].titlelen = strlen(name);
530 return menu->nitems++;
531#else
532 return 0;
533#endif /* CTK_CONF_MENUS */
534}
535/*-----------------------------------------------------------------------------------*/
536static void
537add_redrawwidget(struct ctk_widget *w)
538{
539 static unsigned char i;
540
541 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
542 redraw |= REDRAW_FOCUS;
543 } else {
544 redraw |= REDRAW_WIDGETS;
545 /* Check if it is in the queue already. If so, we don't add it
546 again. */
547 for(i = 0; i < redraw_widgetptr; ++i) {
548 if(redraw_widgets[i] == w) {
549 return;
550 }
551 }
552 redraw_widgets[redraw_widgetptr++] = w;
553 }
554}
555/*-----------------------------------------------------------------------------------*/
556void
557ctk_widget_redraw(struct ctk_widget *widget)
558{
559 struct ctk_window *window;
560
adamdunkels9f667f22003-04-16 18:29:19 +0000561 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000562 return;
563 }
564
565 /* If this function isn't called by CTK itself, we only queue the
566 redraw request. */
567 if(DISPATCHER_CURRENT() != ctkid) {
568 redraw |= REDRAW_WIDGETS;
569 add_redrawwidget(widget);
570 } else {
571
572 /* Only redraw widgets that are in the foremost window. If we
573 would allow redrawing widgets in non-focused windows, we would
574 have to redraw all the windows that cover the non-focused
575 window as well, which would lead to flickering.
576
577 Also, we avoid drawing any widgets when the menus are active.
578 */
579
580#if CTK_CONF_MENUS
581 if(menus.open == NULL)
582#endif /* CTK_CONF_MENUS */
583 {
584 window = widget->window;
585 if(window == dialog) {
586 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
587 } else if(window == windows) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000588 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000589 } else if(window == &desktop_window) {
590 ctk_draw_widget(widget, 0, 0, height);
591 }
592 }
593 }
594}
595/*-----------------------------------------------------------------------------------*/
596void
adamdunkelsd07a5422003-04-05 12:22:35 +0000597ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
598 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000599{
600 if(widget->type == CTK_WIDGET_LABEL ||
601 widget->type == CTK_WIDGET_SEPARATOR) {
602 widget->next = window->inactive;
603 window->inactive = widget;
604 widget->window = window;
605 } else {
606 widget->next = window->active;
607 window->active = widget;
608 widget->window = window;
609 if(window->focused == NULL) {
610 window->focused = widget;
611 }
612 }
613}
614/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000615static void
adamdunkelsb2486562003-04-11 20:22:03 +0000616select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000617{
618 struct ctk_window *window;
619
620 window = focus->window;
621
622 if(focus != window->focused) {
623 window->focused = focus;
624 /* The operation changed the focus, so we emit a "hover" signal
625 for those widgets that support it. */
626
627 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
628 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
629 window->owner);
630 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
631 dispatcher_emit(ctk_signal_button_hover, window->focused,
632 window->owner);
633 }
634
635 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000636
637 dispatcher_emit(ctk_signal_widget_select, focus,
638 focus->window->owner);
639
adamdunkelse0683312003-04-09 09:02:52 +0000640 }
641
642}
643/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000644#define UP 0
645#define DOWN 1
646#define LEFT 2
647#define RIGHT 3
648static void
649switch_focus_widget(unsigned char direction)
650{
651 register struct ctk_window *window;
652 register struct ctk_widget *focus;
653 struct ctk_widget *widget;
654
655
656 if(dialog != NULL) {
657 window = dialog;
658 } else {
659 window = windows;
660 }
661
662 /* If there are no windows open, we move focus around between the
663 icons on the root window instead. */
664 if(window == NULL) {
665 window = &desktop_window;
666 }
667
668 focus = window->focused;
669 add_redrawwidget(focus);
670
671 if((direction & 1) == 0) {
672 /* Move focus "up" */
673 focus = focus->next;
674 } else {
675 /* Move focus "down" */
676 for(widget = window->active;
677 widget != NULL; widget = widget->next) {
678 if(widget->next == focus) {
679 break;
680 }
681 }
682 focus = widget;
683 if(focus == NULL) {
684 if(window->active != NULL) {
685 for(focus = window->active;
686 focus->next != NULL; focus = focus->next);
687 }
688 }
689 }
690 if(focus == NULL) {
691 focus = window->active;
692 }
adamdunkelse0683312003-04-09 09:02:52 +0000693
adamdunkelsb2486562003-04-11 20:22:03 +0000694 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000695}
696/*-----------------------------------------------------------------------------------*/
697#if CTK_CONF_MENUS
698static void
699switch_open_menu(unsigned char rightleft)
700{
701 struct ctk_menu *menu;
702
703 if(rightleft == 0) {
704 /* Move right */
705 for(menu = menus.menus; menu != NULL; menu = menu->next) {
706 if(menu->next == menus.open) {
707 break;
708 }
709 }
710 lastmenu = menus.open;
711 menus.open = menu;
712 if(menus.open == NULL) {
713 for(menu = menus.menus;
714 menu->next != NULL; menu = menu->next);
715 menus.open = menu;
716 }
717 } else {
718 /* Move to left */
719 lastmenu = menus.open;
720 menus.open = menus.open->next;
721 if(menus.open == NULL) {
722 menus.open = menus.menus;
723 }
724 }
725
726 menus.open->active = 0;
727 /* ctk_redraw();*/
728}
729/*-----------------------------------------------------------------------------------*/
730static void
731switch_menu_item(unsigned char updown)
732{
733 register struct ctk_menu *m;
734
735 m = menus.open;
736
737 if(updown == 0) {
738 /* Move up */
739 if(m->active == 0) {
740 m->active = m->nitems - 1;
741 } else {
742 --m->active;
743 if(m->items[m->active].title[0] == '-') {
744 --m->active;
745 }
746 }
747 } else {
748 /* Move down */
749 if(m->active >= m->nitems - 1) {
750 m->active = 0;
751 } else {
752 ++m->active;
753 if(m->items[m->active].title[0] == '-') {
754 ++m->active;
755 }
756 }
757 }
758
759}
760#endif /* CTK_CONF_MENUS */
761/*-----------------------------------------------------------------------------------*/
762static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000763activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000764{
765 static unsigned char len;
766
767 if(w->type == CTK_WIDGET_BUTTON) {
768 if(w == (struct ctk_widget *)&windows->closebutton) {
769#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000770 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000771 ctk_window_close(windows);
772 return REDRAW_ALL;
773#endif /* CTK_CONF_WINDOWCLOSE */
774 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
775#if CTK_CONF_WINDOWCLOSE
776 mode = CTK_MODE_WINDOWMOVE;
777#endif /* CTK_CONF_WINDOWCLOSE */
778 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000779 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000780 w->window->owner);
781 }
782#if CTK_CONF_ICONS
783 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000784 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000785 w->widget.icon.owner);
786#endif /* CTK_CONF_ICONS */
787 } else if(w->type == CTK_WIDGET_HYPERLINK) {
788 dispatcher_emit(ctk_signal_hyperlink_activate, w,
789 DISPATCHER_BROADCAST);
790 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
791 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
792 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
793 len = strlen(w->widget.textentry.text);
794 if(w->widget.textentry.xpos > len) {
795 w->widget.textentry.xpos = len;
796 }
797 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
798 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
799 }
800 add_redrawwidget(w);
801 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000802 } else {
803 dispatcher_emit(ctk_signal_widget_activate, w,
804 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805 }
806 return REDRAW_NONE;
807}
808/*-----------------------------------------------------------------------------------*/
809static void
810textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000811 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000812{
813 static char *cptr, *cptr2;
814 static unsigned char len, txpos, typos, tlen;
815
816 txpos = t->xpos;
817 typos = t->ypos;
818 tlen = t->len;
819
820 cptr = &t->text[txpos + typos * tlen];
821
822 switch(c) {
823 case CH_CURS_LEFT:
824 if(txpos > 0) {
825 --txpos;
826 }
827 break;
828
829 case CH_CURS_RIGHT:
830 if(txpos < tlen &&
831 *cptr != 0) {
832 ++txpos;
833 }
834 break;
835
836 case CH_CURS_UP:
837#if CTK_CONF_TEXTENTRY_MULTILINE
838 if(t->h == 1) {
839 txpos = 0;
840 } else {
841 if(typos > 0) {
842 --typos;
843 } else {
844 t->state = CTK_TEXTENTRY_NORMAL;
845 }
846 }
847#else
848 txpos = 0;
849#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
850 break;
851
852 case CH_CURS_DOWN:
853#if CTK_CONF_TEXTENTRY_MULTILINE
854 if(t->h == 1) {
855 txpos = strlen(t->text);
856 } else {
857 if(typos < t->h - 1) {
858 ++typos;
859 } else {
860 t->state = CTK_TEXTENTRY_NORMAL;
861 }
862 }
863#else
864 txpos = strlen(t->text);
865#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
866 break;
867
868 case CH_ENTER:
869#if CTK_CONF_TEXTENTRY_MULTILINE
870 if(t->h == 1) {
871 t->state = CTK_TEXTENTRY_NORMAL;
872 } else {
873 if(typos < t->h - 1) {
874 ++typos;
875 txpos = 0;
876 } else {
877 t->state = CTK_TEXTENTRY_NORMAL;
878 }
879 }
880#else
881 t->state = CTK_TEXTENTRY_NORMAL;
882#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
883 break;
884
885 default:
886 len = tlen - txpos - 1;
887 if(c == CH_DEL) {
888 if(txpos > 0 && len > 0) {
889 strncpy(cptr - 1, cptr,
890 len);
891 *(cptr + len - 1) = 0;
892 --txpos;
893 }
894 } else {
895 if(len > 0) {
896 cptr2 = cptr + len - 1;
897 while(cptr2 + 1 > cptr) {
898 *(cptr2 + 1) = *cptr2;
899 --cptr2;
900 }
901
902 *cptr = c;
903 ++txpos;
904 }
905 }
906 break;
907 }
908
909 t->xpos = txpos;
910 t->ypos = typos;
911}
912/*-----------------------------------------------------------------------------------*/
913#if CTK_CONF_MENUS
914static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000915activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000916{
917 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000918
919 lastmenu = menus.open;
920 if(menus.open == &desktopmenu) {
921 for(w = windows; w != NULL; w = w->next) {
922 if(w->title == desktopmenu.items[desktopmenu.active].title) {
923 ctk_window_open(w);
924 menus.open = NULL;
925 return REDRAW_ALL;
926 }
927 }
928 } else {
929 dispatcher_emit(ctk_signal_menu_activate, menus.open,
930 DISPATCHER_BROADCAST);
931 }
932 menus.open = NULL;
933 return REDRAW_MENUPART;
934}
935/*-----------------------------------------------------------------------------------*/
936static unsigned char
937menus_input(ctk_arch_key_t c)
938{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000939
940 if(menus.open->nitems > maxnitems) {
941 maxnitems = menus.open->nitems;
942 }
943
944
945 switch(c) {
946 case CH_CURS_RIGHT:
947 switch_open_menu(1);
948
949 return REDRAW_MENUPART;
950
951 case CH_CURS_DOWN:
952 switch_menu_item(1);
953 return REDRAW_MENUS;
954
955 case CH_CURS_LEFT:
956 switch_open_menu(0);
957 return REDRAW_MENUPART;
958
959 case CH_CURS_UP:
960 switch_menu_item(0);
961 return REDRAW_MENUS;
962
963 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000964 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000965
adamdunkels88ed9c42003-03-28 12:10:09 +0000966 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000967 lastmenu = menus.open;
968 menus.open = NULL;
969 return REDRAW_MENUPART;
970 }
adamdunkelsb2486562003-04-11 20:22:03 +0000971
972 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000973}
974#endif /* CTK_CONF_MENUS */
975/*-----------------------------------------------------------------------------------*/
976static void
adamdunkelsc4902862003-04-09 00:30:45 +0000977ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000978{
979 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +0000980 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000981 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +0000982 register struct ctk_widget *widget;
983#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000984 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
985 mouse_clicked;
986 static unsigned char menux;
987 struct ctk_menu *menu;
988
adamdunkels19a787c2003-04-09 09:22:24 +0000989#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000990
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000991#if CTK_CONF_MENUS
992 if(menus.open != NULL) {
993 maxnitems = menus.open->nitems;
994 } else {
995 maxnitems = 0;
996 }
997#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +0000998
999#if CTK_CONF_MOUSE_SUPPORT
1000 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1001
1002 /* See if there is any change in the buttons. */
1003 if(ctk_mouse_button() != mouse_button) {
1004 mouse_button = ctk_mouse_button();
1005 mouse_button_changed = 1;
1006 if(mouse_button == 0) {
1007 mouse_clicked = 1;
1008 }
1009 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001010
adamdunkelsb2486562003-04-11 20:22:03 +00001011 /* Check if the mouse pointer has moved. */
1012 if(ctk_mouse_x() != mouse_x ||
1013 ctk_mouse_y() != mouse_y) {
1014 mouse_x = ctk_mouse_x();
1015 mouse_y = ctk_mouse_y();
1016 mouse_moved = 1;
1017 }
1018
1019 mxc = ctk_mouse_xtoc(mouse_x);
1020 myc = ctk_mouse_ytoc(mouse_y);
1021#endif /* CTK_CONF_MOUSE_SUPPORT */
1022
1023
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001024 if(mode == CTK_MODE_SCREENSAVER) {
1025#ifdef CTK_SCREENSAVER_RUN
1026 CTK_SCREENSAVER_RUN();
1027#endif /* CTK_SCREENSAVER_RUN */
adamdunkelsb2486562003-04-11 20:22:03 +00001028 if(ctk_arch_keyavail()
1029#if CTK_CONF_MOUSE_SUPPORT
1030 || mouse_moved || mouse_button_changed
1031#endif /* CTK_CONF_MOUSE_SUPPORT */
1032 ) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001033 mode = CTK_MODE_NORMAL;
1034 ctk_draw_init();
1035 ctk_redraw();
1036 }
adamdunkelsc4902862003-04-09 00:30:45 +00001037 } else if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001038#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001039 /* If there is any change in the mouse conditions, find out in
1040 which window the mouse pointer currently is in order to send
1041 the correct signals, or bring a window to focus. */
1042 if(mouse_moved || mouse_button_changed) {
1043 ctk_mouse_show();
1044 screensaver_timer = 0;
1045
1046 if(myc == 0) {
1047 /* Here we should do whatever needs to be done when the mouse
1048 moves around and clicks in the menubar. */
1049 if(mouse_clicked) {
1050 /* Find out which menu that the mouse pointer is in. Start
1051 with the ->next menu after the desktop menu. We assume
1052 that the menus start one character from the left screen
1053 side and that the desktop menu is farthest to the
1054 right. */
1055 menux = 1;
1056 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1057 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1058 break;
adamdunkelse0683312003-04-09 09:02:52 +00001059 }
adamdunkelsb2486562003-04-11 20:22:03 +00001060 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001061 }
adamdunkelsb2486562003-04-11 20:22:03 +00001062
1063 /* Also check desktop menu. */
1064 if(mxc >= width - 7 &&
1065 mxc <= width - 1) {
1066 menu = &desktopmenu;
1067 }
1068
1069 menus.open = menu;
1070 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001071 }
adamdunkelse0683312003-04-09 09:02:52 +00001072 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001073 --myc;
1074
1075 if(menus.open != NULL) {
1076 /* Do whatever needs to be done when a menu is open. */
1077
1078 if(menus.open == &desktopmenu) {
1079 menux = width - CTK_CONF_MENUWIDTH;
1080 } else {
1081 menux = 1;
1082 for(menu = menus.menus->next; menu != menus.open;
1083 menu = menu->next) {
1084 menux += menu->titlelen;
1085 }
1086 }
1087
1088 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1089 menus.open->active = myc;
1090 }
1091
1092 if(mouse_clicked) {
1093 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1094 redraw |= activate_menu();
1095 } else {
1096 lastmenu = menus.open;
1097 menus.open = NULL;
1098 redraw |= REDRAW_MENUPART;
1099 }
1100 } else {
1101 redraw |= REDRAW_MENUS;
1102 }
1103 } else {
1104
1105 /* Walk through the windows from top to bottom to see in which
1106 window the mouse pointer is. */
1107 if(dialog != NULL) {
1108 window = dialog;
1109 } else {
1110 for(window = windows; window != NULL; window = window->next) {
1111 /* Check if the mouse is within the window. */
1112 if(mxc >= window->x &&
1113 mxc <= window->x + window->w &&
1114 myc >= window->y &&
1115 myc <= window->y + window->h) {
1116 break;
1117 }
1118 }
1119 }
1120
1121
1122 /* If we didn't find any window, and there are no windows
1123 open, the mouse pointer will definately be within the
1124 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001125 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001126 window = &desktop_window;
1127 }
1128
1129 /* If the mouse pointer moves around outside of the currently
1130 focused window (or dialog), we should not have any focused
1131 widgets in the focused window so we make sure that there
1132 are none. */
1133 if(windows != NULL &&
1134 window != windows &&
1135 windows->focused != NULL){
1136 add_redrawwidget(windows->focused);
1137 windows->focused = NULL;
1138 redraw |= REDRAW_WIDGETS;
1139 }
1140
1141 if(window != NULL) {
1142 /* If the mouse was clicked outside of the current window, we
1143 bring the clicked window to front. */
1144 if(dialog == NULL &&
1145 window != &desktop_window &&
1146 window != windows &&
1147 mouse_clicked) {
1148 /* Bring window to front. */
1149 ctk_window_open(window);
1150 redraw |= REDRAW_ALL;
1151 } else {
1152
1153 /* Find out which widget currently is under the mouse pointer
1154 and give it focus, unless it already has focus. */
1155 mxc = mxc - window->x - 1;
1156 myc = myc - window->y - 1;
1157
1158 /* See if the mouse pointer is on a widget. If so, it should be
1159 selected and, if the button is clicked, activated. */
1160 for(widget = window->active; widget != NULL;
1161 widget = widget->next) {
1162 if(mxc >= widget->x &&
1163 mxc <= widget->x + widget->w &&
1164 (myc == widget->y ||
1165 ((widget->type == CTK_WIDGET_BITMAP ||
1166 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1167 widget->type == CTK_WIDGET_ICON) &&
1168 (myc >= widget->y &&
1169 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1170 break;
1171 }
1172 }
1173
1174
adamdunkels58917a82003-04-18 00:18:38 +00001175 if(mouse_moved &&
1176 (window != &desktop_window ||
1177 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001178 dispatcher_emit(ctk_signal_pointer_move, NULL,
1179 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001180
adamdunkelsb2486562003-04-11 20:22:03 +00001181 if(window->focused != NULL &&
1182 widget != window->focused) {
1183 add_redrawwidget(window->focused);
1184 if(CTK_WIDGET_TYPE(window->focused) ==
1185 CTK_WIDGET_TEXTENTRY) {
1186 ((struct ctk_textentry *)(window->focused))->state =
1187 CTK_TEXTENTRY_NORMAL;
1188 }
1189 window->focused = NULL;
1190 }
1191 redraw |= REDRAW_WIDGETS;
1192 if(widget != NULL) {
1193 select_widget(widget);
1194 }
1195 }
1196
1197 if(mouse_button_changed) {
1198 dispatcher_emit(ctk_signal_pointer_button,
1199 (ek_data_t)mouse_button,
1200 window->owner);
1201 if(mouse_clicked && widget != NULL) {
1202 select_widget(widget);
1203 redraw |= activate(widget);
1204 }
1205 }
1206 }
1207 }
1208 }
adamdunkelsc4902862003-04-09 00:30:45 +00001209 }
1210 }
adamdunkels19a787c2003-04-09 09:22:24 +00001211#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001212
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001213 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001214
1215 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001216
1217 screensaver_timer = 0;
1218
adamdunkelsb2486562003-04-11 20:22:03 +00001219 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001220
1221 if(dialog != NULL) {
1222 window = dialog;
1223 } else if(windows != NULL) {
1224 window = windows;
1225 } else {
1226 window = &desktop_window;
1227 }
1228 widget = window->focused;
1229
1230
1231 if(widget != NULL &&
1232 widget->type == CTK_WIDGET_TEXTENTRY &&
1233 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1234 textentry_input(c, (struct ctk_textentry *)widget);
1235 add_redrawwidget(widget);
1236#if CTK_CONF_MENUS
1237 } else if(menus.open != NULL) {
1238 redraw |= menus_input(c);
1239#endif /* CTK_CONF_MENUS */
1240 } else {
1241 switch(c) {
1242 case CH_CURS_RIGHT:
1243 switch_focus_widget(RIGHT);
1244 break;
1245 case CH_CURS_DOWN:
1246 switch_focus_widget(DOWN);
1247 break;
1248 case CH_CURS_LEFT:
1249 switch_focus_widget(LEFT);
1250 break;
1251 case CH_CURS_UP:
1252 switch_focus_widget(UP);
1253 break;
1254 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001255 if(widget != NULL) {
1256 redraw |= activate(widget);
1257 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001258 break;
1259#if CTK_CONF_MENUS
1260 case CTK_CONF_MENU_KEY:
1261 if(dialog == NULL) {
1262 if(lastmenu == NULL) {
1263 menus.open = menus.menus;
1264 } else {
1265 menus.open = lastmenu;
1266 }
1267 menus.open->active = 0;
1268 redraw |= REDRAW_MENUS;
1269 }
1270 break;
1271#endif /* CTK_CONF_MENUS */
1272 case CTK_CONF_WINDOWSWITCH_KEY:
1273 if(windows != NULL) {
1274 for(window = windows; window->next != NULL;
1275 window = window->next);
1276 ctk_window_open(window);
1277 ctk_redraw();
1278 }
1279 break;
1280 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001281 if(widget != NULL &&
1282 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001283 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1284 textentry_input(c, (struct ctk_textentry *)widget);
1285 add_redrawwidget(widget);
1286 } else {
1287 dispatcher_emit(ctk_signal_keypress, (void *)c,
1288 window->owner);
1289 }
1290 break;
1291 }
1292 }
1293
1294 if(redraw & REDRAW_WIDGETS) {
1295 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001296 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001297 }
1298 redraw &= ~REDRAW_WIDGETS;
1299 redraw_widgetptr = 0;
1300 }
1301 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001302#if CTK_CONF_WINDOWMOVE
1303 } else if(mode == CTK_MODE_WINDOWMOVE) {
1304
1305 redraw = 0;
1306
1307 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001308
1309#if CTK_CONF_MOUSE_SUPPORT
1310
1311 /* If the mouse has moved, we move the window as well. */
1312 if(mouse_moved) {
1313
1314 if(window->w + mxc + 2 >= width) {
1315 window->x = width - 2 - window->w;
1316 } else {
1317 window->x = mxc;
1318 }
1319
1320 if(window->h + myc + 2 >= height) {
1321 window->y = height - 2 - window->h;
1322 } else {
1323 window->y = myc;
1324 }
1325 if(window->y > 0) {
1326 --window->y;
1327 }
1328
1329 redraw = REDRAW_ALL;
1330 }
1331
1332 /* Check if the mouse has been clicked, and stop moving the window
1333 if so. */
1334 if(mouse_button_changed &&
1335 mouse_button == 0) {
1336 mode = CTK_MODE_NORMAL;
1337 redraw = REDRAW_ALL;
1338 }
1339#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001340
1341 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1342
1343 screensaver_timer = 0;
1344
1345 c = ctk_arch_getkey();
1346
1347 switch(c) {
1348 case CH_CURS_RIGHT:
1349 ++window->x;
1350 if(window->x + window->w + 1 >= width) {
1351 --window->x;
1352 }
1353 redraw = REDRAW_ALL;
1354 break;
1355 case CH_CURS_LEFT:
1356 if(window->x > 0) {
1357 --window->x;
1358 }
1359 redraw = REDRAW_ALL;
1360 break;
1361 case CH_CURS_DOWN:
1362 ++window->y;
1363 if(window->y + window->h + 2 >= height) {
1364 --window->y;
1365 }
1366 redraw = REDRAW_ALL;
1367 break;
1368 case CH_CURS_UP:
1369 if(window->y > 0) {
1370 --window->y;
1371 }
1372 redraw = REDRAW_ALL;
1373 break;
1374 case CH_ENTER:
1375 case CH_ESC:
1376 mode = CTK_MODE_NORMAL;
1377 redraw = REDRAW_ALL;
1378 break;
1379 }
1380 }
adamdunkelsb2486562003-04-11 20:22:03 +00001381 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001382 do_redraw_all(1, height);
1383 }
adamdunkelsb2486562003-04-11 20:22:03 +00001384 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001385#endif /* CTK_CONF_WINDOWMOVE */
1386 }
adamdunkelsb2486562003-04-11 20:22:03 +00001387
1388 if(redraw & REDRAW_ALL) {
1389 do_redraw_all(1, height);
1390#if CTK_CONF_MENUS
1391 } else if(redraw & REDRAW_MENUPART) {
1392 do_redraw_all(1, maxnitems + 1);
1393 } else if(redraw & REDRAW_MENUS) {
1394 ctk_draw_menus(&menus);
1395#endif /* CTK_CONF_MENUS */
1396 } else if(redraw & REDRAW_FOCUS) {
1397 if(dialog != NULL) {
1398 ctk_window_redraw(dialog);
1399 } else if(windows != NULL) {
1400 ctk_window_redraw(windows);
1401 } else {
1402 ctk_window_redraw(&desktop_window);
1403 }
1404 } else if(redraw & REDRAW_WIDGETS) {
1405 for(i = 0; i < redraw_widgetptr; ++i) {
1406 ctk_widget_redraw(redraw_widgets[i]);
1407 }
1408 }
1409 redraw = 0;
1410 redraw_widgetptr = 0;
1411
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001412}
1413/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001414static
1415DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001416{
adamdunkels78c03dc2003-04-09 13:45:05 +00001417 DISPATCHER_SIGHANDLER_ARGS(s, data);
1418
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001419 if(s == ctk_signal_timer) {
1420 if(mode == CTK_MODE_NORMAL) {
1421 ++screensaver_timer;
1422 if(screensaver_timer == SCREENSAVER_TIMEOUT) {
1423#ifdef CTK_SCREENSAVER_INIT
1424 CTK_SCREENSAVER_INIT();
1425#endif /* CTK_SCREENSAVER_INIT */
1426 mode = CTK_MODE_SCREENSAVER;
1427 screensaver_timer = 0;
1428 }
1429 }
1430 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1431 }
1432}
1433/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001434