blob: a8aa2c4ba0271e57d956df926a2ec2084d409913 [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 *
adamdunkels66109622003-04-24 17:17:10 +000035 * $Id: ctk.c,v 1.16 2003/04/24 17:17:26 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
adamdunkels66109622003-04-24 17:17:10 +0000105#if CTK_CONF_SCREENSAVER
106ek_signal_t ctk_signal_screensaver_start,
107 ctk_signal_screensaver_stop,
108 ctk_signal_screensaver_uninstall;
109#endif /* CTK_CONF_SCREENSAVER */
110
111
adamdunkels19a787c2003-04-09 09:22:24 +0000112#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000113unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000114#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000115
116static unsigned short screensaver_timer;
117#define SCREENSAVER_TIMEOUT (5*60)
118
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();
175 ctk_signal_timer = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000176
177 ctk_signal_button_activate =
178 ctk_signal_widget_activate = dispatcher_sigalloc();
179
180 ctk_signal_button_hover =
181 ctk_signal_hyperlink_hover =
182 ctk_signal_widget_select = dispatcher_sigalloc();
183
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000184 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000185
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000186 ctk_signal_menu_activate = dispatcher_sigalloc();
187 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000188
189 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000190 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000191
192
193#if CTK_CONF_SCREENSAVER
194 ctk_signal_screensaver_start = dispatcher_sigalloc();
195 ctk_signal_screensaver_stop = dispatcher_sigalloc();
196 ctk_signal_screensaver_uninstall = dispatcher_sigalloc();
197#endif /* CTK_CONF_SCREENSAVER */
198
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000199 dispatcher_listen(ctk_signal_timer);
200 dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
201
202 mode = CTK_MODE_NORMAL;
203
204 iconx = ICONX_START;
205 icony = ICONY_START;
206
207}
208/*-----------------------------------------------------------------------------------*/
209/* void ctk_mode_set()
210 */
211void
212ctk_mode_set(unsigned char m) {
213 mode = m;
214}
215/*-----------------------------------------------------------------------------------*/
216unsigned char
217ctk_mode_get(void) {
218 return mode;
219}
220/*-----------------------------------------------------------------------------------*/
221void
adamdunkelsd07a5422003-04-05 12:22:35 +0000222ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000223 ek_id_t id)
224{
225#if CTK_CONF_ICONS
226 icon->x = iconx;
227 icon->y = icony;
228 icon->widget.icon.owner = id;
229
230 icony += ICONY_DELTA;
231 if(icony >= ICONY_MAX) {
232 icony = ICONY_START;
233 iconx += ICONX_DELTA;
234 }
235
236 ctk_widget_add(&desktop_window, icon);
237#endif /* CTK_CONF_ICONS */
238}
239/*-----------------------------------------------------------------------------------*/
240void
241ctk_dialog_open(struct ctk_window *d)
242{
243 dialog = d;
244}
245/*-----------------------------------------------------------------------------------*/
246void
247ctk_dialog_close(void)
248{
249 dialog = NULL;
250}
251/*-----------------------------------------------------------------------------------*/
252void
adamdunkelsd07a5422003-04-05 12:22:35 +0000253ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000254{
255 struct ctk_window *w2;
256
257 /* Check if already open. */
258 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
259 if(w2 == NULL) {
260 /* Not open, so we add it at the head of the list of open
261 windows. */
262 w->next = windows;
263 if(windows != NULL) {
264 windows->prev = w;
265 }
266 windows = w;
267 w->prev = NULL;
268 } else {
269 /* Window already open, so we move it to the front of the windows
270 list. */
271 if(w != windows) {
272 if(w->next != NULL) {
273 w->next->prev = w->prev;
274 }
275 if(w->prev != NULL) {
276 w->prev->next = w->next;
277 }
278 w->next = windows;
279 windows->prev = w;
280 windows = w;
281 w->prev = NULL;
282 }
283 }
284
285#if CTK_CONF_MENUS
286 /* Recreate the Desktop menu's window entries.*/
287 make_desktopmenu();
288#endif /* CTK_CONF_MENUS */
289}
290/*-----------------------------------------------------------------------------------*/
291void
292ctk_window_close(struct ctk_window *w)
293{
294 struct ctk_window *w2;
295
296 if(w == NULL) {
297 return;
298 }
299
300 /* Check if the window to be closed is the first window on the
301 list. */
302 if(w == windows) {
303 windows = w->next;
304 if(windows != NULL) {
305 windows->prev = NULL;
306 }
307 w->next = w->prev = NULL;
308 } else {
309 /* Otherwise we step through the list until we find the window
310 before the one to be closed. We then redirect its ->next
311 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000312 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
313
314 if(w2 == NULL) {
315 /* The window wasn't open, so there is nothing more for us to
316 do. */
317 return;
318 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000319
320 if(w->next != NULL) {
321 w->next->prev = w->prev;
322 }
323 w2->next = w->next;
324
325 w->next = w->prev = NULL;
326 }
327
328#if CTK_CONF_MENUS
329 /* Recreate the Desktop menu's window entries.*/
330 make_desktopmenu();
331#endif /* CTK_CONF_MENUS */
332}
333/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000334static void
335make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000336{
337#if CTK_CONF_WINDOWMOVE
338 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
339#else
340 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
341#endif /* CTK_CONF_WINDOWMOVE */
342 CTK_WIDGET_ADD(window, &window->titlebutton);
343
344
345#if CTK_CONF_WINDOWCLOSE
346 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
347#else
348 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
349#endif /* CTK_CONF_WINDOWCLOSE */
350 CTK_WIDGET_ADD(window, &window->closebutton);
351}
352/*-----------------------------------------------------------------------------------*/
353void
354ctk_window_clear(struct ctk_window *window)
355{
356 window->active = window->inactive = window->focused = NULL;
357
358 make_windowbuttons(window);
359}
360/*-----------------------------------------------------------------------------------*/
361void
362ctk_menu_add(struct ctk_menu *menu)
363{
364#if CTK_CONF_MENUS
365 struct ctk_menu *m;
366
367 if(lastmenu == NULL) {
368 lastmenu = menu;
369 }
370
371 for(m = menus.menus; m->next != NULL; m = m->next) {
372 if(m == menu) {
373 return;
374 }
375 }
376 m->next = menu;
377 menu->next = NULL;
378#endif /* CTK_CONF_MENUS */
379}
380/*-----------------------------------------------------------------------------------*/
381void
382ctk_menu_remove(struct ctk_menu *menu)
383{
384#if CTK_CONF_MENUS
385 struct ctk_menu *m;
386
387 for(m = menus.menus; m->next != NULL; m = m->next) {
388 if(m->next == menu) {
389 m->next = menu->next;
390 return;
391 }
392 }
393#endif /* CTK_CONF_MENUS */
394}
395/*-----------------------------------------------------------------------------------*/
396static void
397do_redraw_all(unsigned char clipy1, unsigned char clipy2)
398{
399 struct ctk_window *w;
400 struct ctk_widget *widget;
401
402 if(mode != CTK_MODE_NORMAL &&
403 mode != CTK_MODE_WINDOWMOVE) {
404 return;
405 }
406
407 ctk_draw_clear(clipy1, clipy2);
408
409 /* Draw widgets in root window */
410 for(widget = desktop_window.active;
411 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000412 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000413 }
414
415 /* Draw windows */
416 if(windows != NULL) {
417 /* Find the last window.*/
418 for(w = windows; w->next != NULL; w = w->next);
419
420 /* Draw the windows from back to front. */
421 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000422 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000423 ctk_draw_window(w, 0, clipy1, clipy2);
424 }
425 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000426 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000427 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
428 }
429
430 /* Draw dialog (if any) */
431 if(dialog != NULL) {
432 ctk_draw_dialog(dialog);
433 }
434
435#if CTK_CONF_MENUS
436 ctk_draw_menus(&menus);
437#endif /* CTK_CONF_MENUS */
438}
439/*-----------------------------------------------------------------------------------*/
440void
441ctk_redraw(void)
442{
443 if(DISPATCHER_CURRENT() == ctkid) {
444 if(mode == CTK_MODE_NORMAL ||
445 mode == CTK_MODE_WINDOWMOVE) {
446 do_redraw_all(1, height);
447 }
448 } else {
449 redraw |= REDRAW_ALL;
450 }
451}
452/*-----------------------------------------------------------------------------------*/
453void
454ctk_window_redraw(struct ctk_window *w)
455{
456 /* Only redraw the window if it is a dialog or if it is the foremost
457 window. */
458 if(mode != CTK_MODE_NORMAL) {
459 return;
460 }
461
462 if(w == dialog) {
463 ctk_draw_dialog(w);
464 } else if(dialog == NULL &&
465#if CTK_CONF_MENUS
466 menus.open == NULL &&
467#endif /* CTK_CONF_MENUS */
468 windows == w) {
469 ctk_draw_window(w, CTK_FOCUS_WINDOW,
470 0, height);
471 }
472}
473/*-----------------------------------------------------------------------------------*/
474static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000475window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000476 unsigned char w, unsigned char h,
477 char *title)
478{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000479
480 if(w >= width - 2) {
481 window->x = 0;
482 } else {
483 window->x = (width - w - 2) / 2;
484 }
485 if(h >= height - 3) {
486 window->y = 0;
487 } else {
488 window->y = (height - h - 1) / 2;
489 }
490
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000491 window->w = w;
492 window->h = h;
493 window->title = title;
494 if(title != NULL) {
495 window->titlelen = strlen(title);
496 } else {
497 window->titlelen = 0;
498 }
499 window->next = window->prev = NULL;
500 window->owner = DISPATCHER_CURRENT();
501 window->active = window->inactive = window->focused = NULL;
502}
503/*-----------------------------------------------------------------------------------*/
504void
505ctk_window_new(struct ctk_window *window,
506 unsigned char w, unsigned char h,
507 char *title)
508{
509 window_new(window, w, h, title);
510
511 make_windowbuttons(window);
512}
513/*-----------------------------------------------------------------------------------*/
514void
adamdunkelsd07a5422003-04-05 12:22:35 +0000515ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000516 unsigned char w, unsigned char h)
517{
518 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000519}
520/*-----------------------------------------------------------------------------------*/
521void
adamdunkelsd07a5422003-04-05 12:22:35 +0000522ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000523 char *title)
524{
525#if CTK_CONF_MENUS
526 menu->next = NULL;
527 menu->title = title;
528 menu->titlelen = strlen(title);
529 menu->active = 0;
530 menu->nitems = 0;
531#endif /* CTK_CONF_MENUS */
532}
533/*-----------------------------------------------------------------------------------*/
534unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000535ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000536 char *name)
537{
538#if CTK_CONF_MENUS
539 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
540 return 0;
541 }
542 menu->items[menu->nitems].title = name;
543 menu->items[menu->nitems].titlelen = strlen(name);
544 return menu->nitems++;
545#else
546 return 0;
547#endif /* CTK_CONF_MENUS */
548}
549/*-----------------------------------------------------------------------------------*/
550static void
551add_redrawwidget(struct ctk_widget *w)
552{
553 static unsigned char i;
554
555 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
556 redraw |= REDRAW_FOCUS;
557 } else {
558 redraw |= REDRAW_WIDGETS;
559 /* Check if it is in the queue already. If so, we don't add it
560 again. */
561 for(i = 0; i < redraw_widgetptr; ++i) {
562 if(redraw_widgets[i] == w) {
563 return;
564 }
565 }
566 redraw_widgets[redraw_widgetptr++] = w;
567 }
568}
569/*-----------------------------------------------------------------------------------*/
570void
571ctk_widget_redraw(struct ctk_widget *widget)
572{
573 struct ctk_window *window;
574
adamdunkels9f667f22003-04-16 18:29:19 +0000575 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000576 return;
577 }
578
579 /* If this function isn't called by CTK itself, we only queue the
580 redraw request. */
581 if(DISPATCHER_CURRENT() != ctkid) {
582 redraw |= REDRAW_WIDGETS;
583 add_redrawwidget(widget);
584 } else {
585
586 /* Only redraw widgets that are in the foremost window. If we
587 would allow redrawing widgets in non-focused windows, we would
588 have to redraw all the windows that cover the non-focused
589 window as well, which would lead to flickering.
590
591 Also, we avoid drawing any widgets when the menus are active.
592 */
593
594#if CTK_CONF_MENUS
595 if(menus.open == NULL)
596#endif /* CTK_CONF_MENUS */
597 {
598 window = widget->window;
599 if(window == dialog) {
600 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels66109622003-04-24 17:17:10 +0000601 } else if(window == windows ||
602 window == &desktop_window) {
603 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000604 }
605 }
606 }
607}
608/*-----------------------------------------------------------------------------------*/
609void
adamdunkelsd07a5422003-04-05 12:22:35 +0000610ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
611 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000612{
613 if(widget->type == CTK_WIDGET_LABEL ||
614 widget->type == CTK_WIDGET_SEPARATOR) {
615 widget->next = window->inactive;
616 window->inactive = widget;
617 widget->window = window;
618 } else {
619 widget->next = window->active;
620 window->active = widget;
621 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000622 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000623 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000624 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000625 }
626}
627/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000628static void
adamdunkelsb2486562003-04-11 20:22:03 +0000629select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000630{
631 struct ctk_window *window;
632
633 window = focus->window;
634
635 if(focus != window->focused) {
636 window->focused = focus;
637 /* The operation changed the focus, so we emit a "hover" signal
638 for those widgets that support it. */
639
640 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
641 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
642 window->owner);
643 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
644 dispatcher_emit(ctk_signal_button_hover, window->focused,
645 window->owner);
646 }
647
648 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000649
650 dispatcher_emit(ctk_signal_widget_select, focus,
651 focus->window->owner);
652
adamdunkelse0683312003-04-09 09:02:52 +0000653 }
654
655}
656/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000657#define UP 0
658#define DOWN 1
659#define LEFT 2
660#define RIGHT 3
661static void
662switch_focus_widget(unsigned char direction)
663{
664 register struct ctk_window *window;
665 register struct ctk_widget *focus;
666 struct ctk_widget *widget;
667
668
669 if(dialog != NULL) {
670 window = dialog;
671 } else {
672 window = windows;
673 }
674
675 /* If there are no windows open, we move focus around between the
676 icons on the root window instead. */
677 if(window == NULL) {
678 window = &desktop_window;
679 }
680
681 focus = window->focused;
682 add_redrawwidget(focus);
683
684 if((direction & 1) == 0) {
685 /* Move focus "up" */
686 focus = focus->next;
687 } else {
688 /* Move focus "down" */
689 for(widget = window->active;
690 widget != NULL; widget = widget->next) {
691 if(widget->next == focus) {
692 break;
693 }
694 }
695 focus = widget;
696 if(focus == NULL) {
697 if(window->active != NULL) {
698 for(focus = window->active;
699 focus->next != NULL; focus = focus->next);
700 }
701 }
702 }
703 if(focus == NULL) {
704 focus = window->active;
705 }
adamdunkelse0683312003-04-09 09:02:52 +0000706
adamdunkelsb2486562003-04-11 20:22:03 +0000707 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000708}
709/*-----------------------------------------------------------------------------------*/
710#if CTK_CONF_MENUS
711static void
712switch_open_menu(unsigned char rightleft)
713{
714 struct ctk_menu *menu;
715
716 if(rightleft == 0) {
717 /* Move right */
718 for(menu = menus.menus; menu != NULL; menu = menu->next) {
719 if(menu->next == menus.open) {
720 break;
721 }
722 }
723 lastmenu = menus.open;
724 menus.open = menu;
725 if(menus.open == NULL) {
726 for(menu = menus.menus;
727 menu->next != NULL; menu = menu->next);
728 menus.open = menu;
729 }
730 } else {
731 /* Move to left */
732 lastmenu = menus.open;
733 menus.open = menus.open->next;
734 if(menus.open == NULL) {
735 menus.open = menus.menus;
736 }
737 }
738
adamdunkels66109622003-04-24 17:17:10 +0000739 menus.open->active = 0;
740
741 /* if(menus.open->nitems > maxnitems) {
742 maxnitems = menus.open->nitems;
743 }*/
744
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000745 /* ctk_redraw();*/
746}
747/*-----------------------------------------------------------------------------------*/
748static void
749switch_menu_item(unsigned char updown)
750{
751 register struct ctk_menu *m;
752
753 m = menus.open;
754
755 if(updown == 0) {
756 /* Move up */
757 if(m->active == 0) {
758 m->active = m->nitems - 1;
759 } else {
760 --m->active;
761 if(m->items[m->active].title[0] == '-') {
762 --m->active;
763 }
764 }
765 } else {
766 /* Move down */
767 if(m->active >= m->nitems - 1) {
768 m->active = 0;
769 } else {
770 ++m->active;
771 if(m->items[m->active].title[0] == '-') {
772 ++m->active;
773 }
774 }
775 }
776
777}
778#endif /* CTK_CONF_MENUS */
779/*-----------------------------------------------------------------------------------*/
780static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000781activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000782{
783 static unsigned char len;
784
785 if(w->type == CTK_WIDGET_BUTTON) {
786 if(w == (struct ctk_widget *)&windows->closebutton) {
787#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000788 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000789 ctk_window_close(windows);
790 return REDRAW_ALL;
791#endif /* CTK_CONF_WINDOWCLOSE */
792 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
793#if CTK_CONF_WINDOWCLOSE
794 mode = CTK_MODE_WINDOWMOVE;
795#endif /* CTK_CONF_WINDOWCLOSE */
796 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000797 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000798 w->window->owner);
799 }
800#if CTK_CONF_ICONS
801 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000802 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000803 w->widget.icon.owner);
804#endif /* CTK_CONF_ICONS */
805 } else if(w->type == CTK_WIDGET_HYPERLINK) {
806 dispatcher_emit(ctk_signal_hyperlink_activate, w,
807 DISPATCHER_BROADCAST);
808 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
809 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
810 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
811 len = strlen(w->widget.textentry.text);
812 if(w->widget.textentry.xpos > len) {
813 w->widget.textentry.xpos = len;
814 }
815 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
816 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
817 }
818 add_redrawwidget(w);
819 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000820 } else {
821 dispatcher_emit(ctk_signal_widget_activate, w,
822 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000823 }
824 return REDRAW_NONE;
825}
826/*-----------------------------------------------------------------------------------*/
827static void
828textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000829 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000830{
831 static char *cptr, *cptr2;
832 static unsigned char len, txpos, typos, tlen;
833
834 txpos = t->xpos;
835 typos = t->ypos;
836 tlen = t->len;
837
838 cptr = &t->text[txpos + typos * tlen];
839
840 switch(c) {
841 case CH_CURS_LEFT:
842 if(txpos > 0) {
843 --txpos;
844 }
845 break;
846
847 case CH_CURS_RIGHT:
848 if(txpos < tlen &&
849 *cptr != 0) {
850 ++txpos;
851 }
852 break;
853
854 case CH_CURS_UP:
855#if CTK_CONF_TEXTENTRY_MULTILINE
856 if(t->h == 1) {
857 txpos = 0;
858 } else {
859 if(typos > 0) {
860 --typos;
861 } else {
862 t->state = CTK_TEXTENTRY_NORMAL;
863 }
864 }
865#else
866 txpos = 0;
867#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
868 break;
869
870 case CH_CURS_DOWN:
871#if CTK_CONF_TEXTENTRY_MULTILINE
872 if(t->h == 1) {
873 txpos = strlen(t->text);
874 } else {
875 if(typos < t->h - 1) {
876 ++typos;
877 } else {
878 t->state = CTK_TEXTENTRY_NORMAL;
879 }
880 }
881#else
882 txpos = strlen(t->text);
883#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
884 break;
885
886 case CH_ENTER:
887#if CTK_CONF_TEXTENTRY_MULTILINE
888 if(t->h == 1) {
889 t->state = CTK_TEXTENTRY_NORMAL;
890 } else {
891 if(typos < t->h - 1) {
892 ++typos;
893 txpos = 0;
894 } else {
895 t->state = CTK_TEXTENTRY_NORMAL;
896 }
897 }
898#else
899 t->state = CTK_TEXTENTRY_NORMAL;
900#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
901 break;
902
903 default:
904 len = tlen - txpos - 1;
905 if(c == CH_DEL) {
906 if(txpos > 0 && len > 0) {
907 strncpy(cptr - 1, cptr,
908 len);
909 *(cptr + len - 1) = 0;
910 --txpos;
911 }
912 } else {
913 if(len > 0) {
914 cptr2 = cptr + len - 1;
915 while(cptr2 + 1 > cptr) {
916 *(cptr2 + 1) = *cptr2;
917 --cptr2;
918 }
919
920 *cptr = c;
921 ++txpos;
922 }
923 }
924 break;
925 }
926
927 t->xpos = txpos;
928 t->ypos = typos;
929}
930/*-----------------------------------------------------------------------------------*/
931#if CTK_CONF_MENUS
932static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000933activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000934{
935 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000936
937 lastmenu = menus.open;
938 if(menus.open == &desktopmenu) {
939 for(w = windows; w != NULL; w = w->next) {
940 if(w->title == desktopmenu.items[desktopmenu.active].title) {
941 ctk_window_open(w);
942 menus.open = NULL;
943 return REDRAW_ALL;
944 }
945 }
946 } else {
947 dispatcher_emit(ctk_signal_menu_activate, menus.open,
948 DISPATCHER_BROADCAST);
949 }
950 menus.open = NULL;
951 return REDRAW_MENUPART;
952}
953/*-----------------------------------------------------------------------------------*/
954static unsigned char
955menus_input(ctk_arch_key_t c)
956{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000957
958 if(menus.open->nitems > maxnitems) {
959 maxnitems = menus.open->nitems;
960 }
961
962
963 switch(c) {
964 case CH_CURS_RIGHT:
965 switch_open_menu(1);
966
967 return REDRAW_MENUPART;
968
969 case CH_CURS_DOWN:
970 switch_menu_item(1);
971 return REDRAW_MENUS;
972
973 case CH_CURS_LEFT:
974 switch_open_menu(0);
975 return REDRAW_MENUPART;
976
977 case CH_CURS_UP:
978 switch_menu_item(0);
979 return REDRAW_MENUS;
980
981 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000982 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000983
adamdunkels88ed9c42003-03-28 12:10:09 +0000984 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000985 lastmenu = menus.open;
986 menus.open = NULL;
987 return REDRAW_MENUPART;
988 }
adamdunkelsb2486562003-04-11 20:22:03 +0000989
990 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000991}
992#endif /* CTK_CONF_MENUS */
993/*-----------------------------------------------------------------------------------*/
994static void
adamdunkelsc4902862003-04-09 00:30:45 +0000995ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000996{
997 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +0000998 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000999 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001000 register struct ctk_widget *widget;
1001#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001002 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1003 mouse_clicked;
1004 static unsigned char menux;
1005 struct ctk_menu *menu;
1006
adamdunkels19a787c2003-04-09 09:22:24 +00001007#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001008
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009#if CTK_CONF_MENUS
1010 if(menus.open != NULL) {
1011 maxnitems = menus.open->nitems;
1012 } else {
1013 maxnitems = 0;
1014 }
1015#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001016
1017#if CTK_CONF_MOUSE_SUPPORT
1018 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1019
1020 /* See if there is any change in the buttons. */
1021 if(ctk_mouse_button() != mouse_button) {
1022 mouse_button = ctk_mouse_button();
1023 mouse_button_changed = 1;
1024 if(mouse_button == 0) {
1025 mouse_clicked = 1;
1026 }
1027 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001028
adamdunkelsb2486562003-04-11 20:22:03 +00001029 /* Check if the mouse pointer has moved. */
1030 if(ctk_mouse_x() != mouse_x ||
1031 ctk_mouse_y() != mouse_y) {
1032 mouse_x = ctk_mouse_x();
1033 mouse_y = ctk_mouse_y();
1034 mouse_moved = 1;
1035 }
1036
1037 mxc = ctk_mouse_xtoc(mouse_x);
1038 myc = ctk_mouse_ytoc(mouse_y);
1039#endif /* CTK_CONF_MOUSE_SUPPORT */
1040
1041
adamdunkels66109622003-04-24 17:17:10 +00001042#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001043 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkels66109622003-04-24 17:17:10 +00001044#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001045#ifdef CTK_SCREENSAVER_RUN
1046 CTK_SCREENSAVER_RUN();
1047#endif /* CTK_SCREENSAVER_RUN */
adamdunkels66109622003-04-24 17:17:10 +00001048#endif /* 0 */
adamdunkelsb2486562003-04-11 20:22:03 +00001049 if(ctk_arch_keyavail()
1050#if CTK_CONF_MOUSE_SUPPORT
1051 || mouse_moved || mouse_button_changed
1052#endif /* CTK_CONF_MOUSE_SUPPORT */
1053 ) {
adamdunkels66109622003-04-24 17:17:10 +00001054 dispatcher_emit(ctk_signal_screensaver_stop, NULL, DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001055 mode = CTK_MODE_NORMAL;
adamdunkels66109622003-04-24 17:17:10 +00001056 /* ctk_draw_init();
1057 ctk_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001058 }
adamdunkels66109622003-04-24 17:17:10 +00001059 } else
1060#endif /* CTK_CONF_SCREENSAVER */
1061 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001062#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001063 /* If there is any change in the mouse conditions, find out in
1064 which window the mouse pointer currently is in order to send
1065 the correct signals, or bring a window to focus. */
1066 if(mouse_moved || mouse_button_changed) {
1067 ctk_mouse_show();
1068 screensaver_timer = 0;
1069
1070 if(myc == 0) {
1071 /* Here we should do whatever needs to be done when the mouse
1072 moves around and clicks in the menubar. */
1073 if(mouse_clicked) {
1074 /* Find out which menu that the mouse pointer is in. Start
1075 with the ->next menu after the desktop menu. We assume
1076 that the menus start one character from the left screen
1077 side and that the desktop menu is farthest to the
1078 right. */
1079 menux = 1;
1080 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1081 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1082 break;
adamdunkelse0683312003-04-09 09:02:52 +00001083 }
adamdunkelsb2486562003-04-11 20:22:03 +00001084 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001085 }
adamdunkelsb2486562003-04-11 20:22:03 +00001086
1087 /* Also check desktop menu. */
1088 if(mxc >= width - 7 &&
1089 mxc <= width - 1) {
1090 menu = &desktopmenu;
1091 }
1092
1093 menus.open = menu;
1094 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001095 }
adamdunkelse0683312003-04-09 09:02:52 +00001096 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001097 --myc;
1098
1099 if(menus.open != NULL) {
1100 /* Do whatever needs to be done when a menu is open. */
1101
1102 if(menus.open == &desktopmenu) {
1103 menux = width - CTK_CONF_MENUWIDTH;
1104 } else {
1105 menux = 1;
1106 for(menu = menus.menus->next; menu != menus.open;
1107 menu = menu->next) {
1108 menux += menu->titlelen;
1109 }
1110 }
1111
1112 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1113 menus.open->active = myc;
1114 }
1115
1116 if(mouse_clicked) {
1117 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1118 redraw |= activate_menu();
1119 } else {
1120 lastmenu = menus.open;
1121 menus.open = NULL;
1122 redraw |= REDRAW_MENUPART;
1123 }
1124 } else {
1125 redraw |= REDRAW_MENUS;
1126 }
1127 } else {
1128
1129 /* Walk through the windows from top to bottom to see in which
1130 window the mouse pointer is. */
1131 if(dialog != NULL) {
1132 window = dialog;
1133 } else {
1134 for(window = windows; window != NULL; window = window->next) {
1135 /* Check if the mouse is within the window. */
1136 if(mxc >= window->x &&
1137 mxc <= window->x + window->w &&
1138 myc >= window->y &&
1139 myc <= window->y + window->h) {
1140 break;
1141 }
1142 }
1143 }
1144
1145
1146 /* If we didn't find any window, and there are no windows
1147 open, the mouse pointer will definately be within the
1148 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001149 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001150 window = &desktop_window;
1151 }
1152
1153 /* If the mouse pointer moves around outside of the currently
1154 focused window (or dialog), we should not have any focused
1155 widgets in the focused window so we make sure that there
1156 are none. */
1157 if(windows != NULL &&
1158 window != windows &&
1159 windows->focused != NULL){
1160 add_redrawwidget(windows->focused);
1161 windows->focused = NULL;
1162 redraw |= REDRAW_WIDGETS;
1163 }
1164
1165 if(window != NULL) {
1166 /* If the mouse was clicked outside of the current window, we
1167 bring the clicked window to front. */
1168 if(dialog == NULL &&
1169 window != &desktop_window &&
1170 window != windows &&
1171 mouse_clicked) {
1172 /* Bring window to front. */
1173 ctk_window_open(window);
1174 redraw |= REDRAW_ALL;
1175 } else {
1176
1177 /* Find out which widget currently is under the mouse pointer
1178 and give it focus, unless it already has focus. */
1179 mxc = mxc - window->x - 1;
1180 myc = myc - window->y - 1;
1181
1182 /* See if the mouse pointer is on a widget. If so, it should be
1183 selected and, if the button is clicked, activated. */
1184 for(widget = window->active; widget != NULL;
1185 widget = widget->next) {
1186 if(mxc >= widget->x &&
1187 mxc <= widget->x + widget->w &&
1188 (myc == widget->y ||
1189 ((widget->type == CTK_WIDGET_BITMAP ||
1190 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1191 widget->type == CTK_WIDGET_ICON) &&
1192 (myc >= widget->y &&
1193 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1194 break;
1195 }
1196 }
1197
1198
adamdunkels58917a82003-04-18 00:18:38 +00001199 if(mouse_moved &&
1200 (window != &desktop_window ||
1201 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001202 dispatcher_emit(ctk_signal_pointer_move, NULL,
1203 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001204
adamdunkelsb2486562003-04-11 20:22:03 +00001205 if(window->focused != NULL &&
1206 widget != window->focused) {
1207 add_redrawwidget(window->focused);
1208 if(CTK_WIDGET_TYPE(window->focused) ==
1209 CTK_WIDGET_TEXTENTRY) {
1210 ((struct ctk_textentry *)(window->focused))->state =
1211 CTK_TEXTENTRY_NORMAL;
1212 }
1213 window->focused = NULL;
1214 }
1215 redraw |= REDRAW_WIDGETS;
1216 if(widget != NULL) {
1217 select_widget(widget);
1218 }
1219 }
1220
1221 if(mouse_button_changed) {
1222 dispatcher_emit(ctk_signal_pointer_button,
1223 (ek_data_t)mouse_button,
1224 window->owner);
1225 if(mouse_clicked && widget != NULL) {
1226 select_widget(widget);
1227 redraw |= activate(widget);
1228 }
1229 }
1230 }
1231 }
1232 }
adamdunkelsc4902862003-04-09 00:30:45 +00001233 }
1234 }
adamdunkels19a787c2003-04-09 09:22:24 +00001235#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001236
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001237 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001238
1239 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001240
1241 screensaver_timer = 0;
1242
adamdunkelsb2486562003-04-11 20:22:03 +00001243 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001244
1245 if(dialog != NULL) {
1246 window = dialog;
1247 } else if(windows != NULL) {
1248 window = windows;
1249 } else {
1250 window = &desktop_window;
1251 }
1252 widget = window->focused;
1253
1254
1255 if(widget != NULL &&
1256 widget->type == CTK_WIDGET_TEXTENTRY &&
1257 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1258 textentry_input(c, (struct ctk_textentry *)widget);
1259 add_redrawwidget(widget);
1260#if CTK_CONF_MENUS
1261 } else if(menus.open != NULL) {
1262 redraw |= menus_input(c);
1263#endif /* CTK_CONF_MENUS */
1264 } else {
1265 switch(c) {
1266 case CH_CURS_RIGHT:
1267 switch_focus_widget(RIGHT);
1268 break;
1269 case CH_CURS_DOWN:
1270 switch_focus_widget(DOWN);
1271 break;
1272 case CH_CURS_LEFT:
1273 switch_focus_widget(LEFT);
1274 break;
1275 case CH_CURS_UP:
1276 switch_focus_widget(UP);
1277 break;
1278 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001279 if(widget != NULL) {
1280 redraw |= activate(widget);
1281 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001282 break;
1283#if CTK_CONF_MENUS
1284 case CTK_CONF_MENU_KEY:
1285 if(dialog == NULL) {
1286 if(lastmenu == NULL) {
1287 menus.open = menus.menus;
1288 } else {
1289 menus.open = lastmenu;
1290 }
1291 menus.open->active = 0;
1292 redraw |= REDRAW_MENUS;
1293 }
1294 break;
1295#endif /* CTK_CONF_MENUS */
1296 case CTK_CONF_WINDOWSWITCH_KEY:
1297 if(windows != NULL) {
1298 for(window = windows; window->next != NULL;
1299 window = window->next);
1300 ctk_window_open(window);
1301 ctk_redraw();
1302 }
1303 break;
1304 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001305 if(widget != NULL &&
1306 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001307 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1308 textentry_input(c, (struct ctk_textentry *)widget);
1309 add_redrawwidget(widget);
1310 } else {
1311 dispatcher_emit(ctk_signal_keypress, (void *)c,
1312 window->owner);
1313 }
1314 break;
1315 }
1316 }
1317
1318 if(redraw & REDRAW_WIDGETS) {
1319 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001320 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001321 }
1322 redraw &= ~REDRAW_WIDGETS;
1323 redraw_widgetptr = 0;
1324 }
1325 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001326#if CTK_CONF_WINDOWMOVE
1327 } else if(mode == CTK_MODE_WINDOWMOVE) {
1328
1329 redraw = 0;
1330
1331 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001332
1333#if CTK_CONF_MOUSE_SUPPORT
1334
1335 /* If the mouse has moved, we move the window as well. */
1336 if(mouse_moved) {
1337
1338 if(window->w + mxc + 2 >= width) {
1339 window->x = width - 2 - window->w;
1340 } else {
1341 window->x = mxc;
1342 }
1343
1344 if(window->h + myc + 2 >= height) {
1345 window->y = height - 2 - window->h;
1346 } else {
1347 window->y = myc;
1348 }
1349 if(window->y > 0) {
1350 --window->y;
1351 }
1352
1353 redraw = REDRAW_ALL;
1354 }
1355
1356 /* Check if the mouse has been clicked, and stop moving the window
1357 if so. */
1358 if(mouse_button_changed &&
1359 mouse_button == 0) {
1360 mode = CTK_MODE_NORMAL;
1361 redraw = REDRAW_ALL;
1362 }
1363#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364
1365 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1366
1367 screensaver_timer = 0;
1368
1369 c = ctk_arch_getkey();
1370
1371 switch(c) {
1372 case CH_CURS_RIGHT:
1373 ++window->x;
1374 if(window->x + window->w + 1 >= width) {
1375 --window->x;
1376 }
1377 redraw = REDRAW_ALL;
1378 break;
1379 case CH_CURS_LEFT:
1380 if(window->x > 0) {
1381 --window->x;
1382 }
1383 redraw = REDRAW_ALL;
1384 break;
1385 case CH_CURS_DOWN:
1386 ++window->y;
1387 if(window->y + window->h + 2 >= height) {
1388 --window->y;
1389 }
1390 redraw = REDRAW_ALL;
1391 break;
1392 case CH_CURS_UP:
1393 if(window->y > 0) {
1394 --window->y;
1395 }
1396 redraw = REDRAW_ALL;
1397 break;
1398 case CH_ENTER:
1399 case CH_ESC:
1400 mode = CTK_MODE_NORMAL;
1401 redraw = REDRAW_ALL;
1402 break;
1403 }
1404 }
adamdunkelsb2486562003-04-11 20:22:03 +00001405 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001406 do_redraw_all(1, height);
1407 }
adamdunkelsb2486562003-04-11 20:22:03 +00001408 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001409#endif /* CTK_CONF_WINDOWMOVE */
1410 }
adamdunkelsb2486562003-04-11 20:22:03 +00001411
1412 if(redraw & REDRAW_ALL) {
1413 do_redraw_all(1, height);
1414#if CTK_CONF_MENUS
1415 } else if(redraw & REDRAW_MENUPART) {
1416 do_redraw_all(1, maxnitems + 1);
1417 } else if(redraw & REDRAW_MENUS) {
1418 ctk_draw_menus(&menus);
1419#endif /* CTK_CONF_MENUS */
1420 } else if(redraw & REDRAW_FOCUS) {
1421 if(dialog != NULL) {
1422 ctk_window_redraw(dialog);
1423 } else if(windows != NULL) {
1424 ctk_window_redraw(windows);
1425 } else {
1426 ctk_window_redraw(&desktop_window);
1427 }
1428 } else if(redraw & REDRAW_WIDGETS) {
1429 for(i = 0; i < redraw_widgetptr; ++i) {
1430 ctk_widget_redraw(redraw_widgets[i]);
1431 }
1432 }
1433 redraw = 0;
1434 redraw_widgetptr = 0;
1435
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001436}
1437/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001438static
1439DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001440{
adamdunkels78c03dc2003-04-09 13:45:05 +00001441 DISPATCHER_SIGHANDLER_ARGS(s, data);
1442
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001443 if(s == ctk_signal_timer) {
1444 if(mode == CTK_MODE_NORMAL) {
1445 ++screensaver_timer;
1446 if(screensaver_timer == SCREENSAVER_TIMEOUT) {
adamdunkels66109622003-04-24 17:17:10 +00001447#if CTK_CONF_SCREENSAVER
1448 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1449 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001450#ifdef CTK_SCREENSAVER_INIT
1451 CTK_SCREENSAVER_INIT();
1452#endif /* CTK_SCREENSAVER_INIT */
1453 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001454#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001455 screensaver_timer = 0;
1456 }
1457 }
1458 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1459 }
1460}
1461/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001462