blob: db67c3a752a64fc721ebaa5b808d096781a3aa48 [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 *
adamdunkelse8bdfe12003-04-25 08:49:17 +000035 * $Id: ctk.c,v 1.17 2003/04/25 08:49:17 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;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000682 if(focus == NULL) {
683 focus = window->active;
684 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000685 add_redrawwidget(focus);
686
687 if((direction & 1) == 0) {
688 /* Move focus "up" */
689 focus = focus->next;
690 } else {
691 /* Move focus "down" */
692 for(widget = window->active;
693 widget != NULL; widget = widget->next) {
694 if(widget->next == focus) {
695 break;
696 }
697 }
698 focus = widget;
699 if(focus == NULL) {
700 if(window->active != NULL) {
701 for(focus = window->active;
702 focus->next != NULL; focus = focus->next);
703 }
704 }
705 }
706 if(focus == NULL) {
707 focus = window->active;
708 }
adamdunkelse0683312003-04-09 09:02:52 +0000709
adamdunkelsb2486562003-04-11 20:22:03 +0000710 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000711}
712/*-----------------------------------------------------------------------------------*/
713#if CTK_CONF_MENUS
714static void
715switch_open_menu(unsigned char rightleft)
716{
717 struct ctk_menu *menu;
718
719 if(rightleft == 0) {
720 /* Move right */
721 for(menu = menus.menus; menu != NULL; menu = menu->next) {
722 if(menu->next == menus.open) {
723 break;
724 }
725 }
726 lastmenu = menus.open;
727 menus.open = menu;
728 if(menus.open == NULL) {
729 for(menu = menus.menus;
730 menu->next != NULL; menu = menu->next);
731 menus.open = menu;
732 }
733 } else {
734 /* Move to left */
735 lastmenu = menus.open;
736 menus.open = menus.open->next;
737 if(menus.open == NULL) {
738 menus.open = menus.menus;
739 }
740 }
741
adamdunkels66109622003-04-24 17:17:10 +0000742 menus.open->active = 0;
743
744 /* if(menus.open->nitems > maxnitems) {
745 maxnitems = menus.open->nitems;
746 }*/
747
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000748 /* ctk_redraw();*/
749}
750/*-----------------------------------------------------------------------------------*/
751static void
752switch_menu_item(unsigned char updown)
753{
754 register struct ctk_menu *m;
755
756 m = menus.open;
757
758 if(updown == 0) {
759 /* Move up */
760 if(m->active == 0) {
761 m->active = m->nitems - 1;
762 } else {
763 --m->active;
764 if(m->items[m->active].title[0] == '-') {
765 --m->active;
766 }
767 }
768 } else {
769 /* Move down */
770 if(m->active >= m->nitems - 1) {
771 m->active = 0;
772 } else {
773 ++m->active;
774 if(m->items[m->active].title[0] == '-') {
775 ++m->active;
776 }
777 }
778 }
779
780}
781#endif /* CTK_CONF_MENUS */
782/*-----------------------------------------------------------------------------------*/
783static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000784activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000785{
786 static unsigned char len;
787
788 if(w->type == CTK_WIDGET_BUTTON) {
789 if(w == (struct ctk_widget *)&windows->closebutton) {
790#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000791 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000792 ctk_window_close(windows);
793 return REDRAW_ALL;
794#endif /* CTK_CONF_WINDOWCLOSE */
795 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
796#if CTK_CONF_WINDOWCLOSE
797 mode = CTK_MODE_WINDOWMOVE;
798#endif /* CTK_CONF_WINDOWCLOSE */
799 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000800 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000801 w->window->owner);
802 }
803#if CTK_CONF_ICONS
804 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000805 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000806 w->widget.icon.owner);
807#endif /* CTK_CONF_ICONS */
808 } else if(w->type == CTK_WIDGET_HYPERLINK) {
809 dispatcher_emit(ctk_signal_hyperlink_activate, w,
810 DISPATCHER_BROADCAST);
811 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
812 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
813 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
814 len = strlen(w->widget.textentry.text);
815 if(w->widget.textentry.xpos > len) {
816 w->widget.textentry.xpos = len;
817 }
818 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
819 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
820 }
821 add_redrawwidget(w);
822 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000823 } else {
824 dispatcher_emit(ctk_signal_widget_activate, w,
825 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826 }
827 return REDRAW_NONE;
828}
829/*-----------------------------------------------------------------------------------*/
830static void
831textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000832 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000833{
834 static char *cptr, *cptr2;
835 static unsigned char len, txpos, typos, tlen;
836
837 txpos = t->xpos;
838 typos = t->ypos;
839 tlen = t->len;
840
841 cptr = &t->text[txpos + typos * tlen];
842
843 switch(c) {
844 case CH_CURS_LEFT:
845 if(txpos > 0) {
846 --txpos;
847 }
848 break;
849
850 case CH_CURS_RIGHT:
851 if(txpos < tlen &&
852 *cptr != 0) {
853 ++txpos;
854 }
855 break;
856
857 case CH_CURS_UP:
858#if CTK_CONF_TEXTENTRY_MULTILINE
859 if(t->h == 1) {
860 txpos = 0;
861 } else {
862 if(typos > 0) {
863 --typos;
864 } else {
865 t->state = CTK_TEXTENTRY_NORMAL;
866 }
867 }
868#else
869 txpos = 0;
870#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
871 break;
872
873 case CH_CURS_DOWN:
874#if CTK_CONF_TEXTENTRY_MULTILINE
875 if(t->h == 1) {
876 txpos = strlen(t->text);
877 } else {
878 if(typos < t->h - 1) {
879 ++typos;
880 } else {
881 t->state = CTK_TEXTENTRY_NORMAL;
882 }
883 }
884#else
885 txpos = strlen(t->text);
886#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
887 break;
888
889 case CH_ENTER:
890#if CTK_CONF_TEXTENTRY_MULTILINE
891 if(t->h == 1) {
892 t->state = CTK_TEXTENTRY_NORMAL;
893 } else {
894 if(typos < t->h - 1) {
895 ++typos;
896 txpos = 0;
897 } else {
898 t->state = CTK_TEXTENTRY_NORMAL;
899 }
900 }
901#else
902 t->state = CTK_TEXTENTRY_NORMAL;
903#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
904 break;
905
906 default:
907 len = tlen - txpos - 1;
908 if(c == CH_DEL) {
909 if(txpos > 0 && len > 0) {
910 strncpy(cptr - 1, cptr,
911 len);
912 *(cptr + len - 1) = 0;
913 --txpos;
914 }
915 } else {
916 if(len > 0) {
917 cptr2 = cptr + len - 1;
918 while(cptr2 + 1 > cptr) {
919 *(cptr2 + 1) = *cptr2;
920 --cptr2;
921 }
922
923 *cptr = c;
924 ++txpos;
925 }
926 }
927 break;
928 }
929
930 t->xpos = txpos;
931 t->ypos = typos;
932}
933/*-----------------------------------------------------------------------------------*/
934#if CTK_CONF_MENUS
935static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000936activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000937{
938 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000939
940 lastmenu = menus.open;
941 if(menus.open == &desktopmenu) {
942 for(w = windows; w != NULL; w = w->next) {
943 if(w->title == desktopmenu.items[desktopmenu.active].title) {
944 ctk_window_open(w);
945 menus.open = NULL;
946 return REDRAW_ALL;
947 }
948 }
949 } else {
950 dispatcher_emit(ctk_signal_menu_activate, menus.open,
951 DISPATCHER_BROADCAST);
952 }
953 menus.open = NULL;
954 return REDRAW_MENUPART;
955}
956/*-----------------------------------------------------------------------------------*/
957static unsigned char
958menus_input(ctk_arch_key_t c)
959{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000960
961 if(menus.open->nitems > maxnitems) {
962 maxnitems = menus.open->nitems;
963 }
964
965
966 switch(c) {
967 case CH_CURS_RIGHT:
968 switch_open_menu(1);
969
970 return REDRAW_MENUPART;
971
972 case CH_CURS_DOWN:
973 switch_menu_item(1);
974 return REDRAW_MENUS;
975
976 case CH_CURS_LEFT:
977 switch_open_menu(0);
978 return REDRAW_MENUPART;
979
980 case CH_CURS_UP:
981 switch_menu_item(0);
982 return REDRAW_MENUS;
983
984 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000985 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986
adamdunkels88ed9c42003-03-28 12:10:09 +0000987 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000988 lastmenu = menus.open;
989 menus.open = NULL;
990 return REDRAW_MENUPART;
991 }
adamdunkelsb2486562003-04-11 20:22:03 +0000992
993 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000994}
995#endif /* CTK_CONF_MENUS */
996/*-----------------------------------------------------------------------------------*/
997static void
adamdunkelsc4902862003-04-09 00:30:45 +0000998ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000999{
1000 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001001 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001002 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001003 register struct ctk_widget *widget;
1004#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001005 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1006 mouse_clicked;
1007 static unsigned char menux;
1008 struct ctk_menu *menu;
1009
adamdunkels19a787c2003-04-09 09:22:24 +00001010#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001011
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001012#if CTK_CONF_MENUS
1013 if(menus.open != NULL) {
1014 maxnitems = menus.open->nitems;
1015 } else {
1016 maxnitems = 0;
1017 }
1018#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001019
1020#if CTK_CONF_MOUSE_SUPPORT
1021 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1022
1023 /* See if there is any change in the buttons. */
1024 if(ctk_mouse_button() != mouse_button) {
1025 mouse_button = ctk_mouse_button();
1026 mouse_button_changed = 1;
1027 if(mouse_button == 0) {
1028 mouse_clicked = 1;
1029 }
1030 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001031
adamdunkelsb2486562003-04-11 20:22:03 +00001032 /* Check if the mouse pointer has moved. */
1033 if(ctk_mouse_x() != mouse_x ||
1034 ctk_mouse_y() != mouse_y) {
1035 mouse_x = ctk_mouse_x();
1036 mouse_y = ctk_mouse_y();
1037 mouse_moved = 1;
1038 }
1039
1040 mxc = ctk_mouse_xtoc(mouse_x);
1041 myc = ctk_mouse_ytoc(mouse_y);
1042#endif /* CTK_CONF_MOUSE_SUPPORT */
1043
1044
adamdunkels66109622003-04-24 17:17:10 +00001045#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001046 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkels66109622003-04-24 17:17:10 +00001047#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001048#ifdef CTK_SCREENSAVER_RUN
1049 CTK_SCREENSAVER_RUN();
1050#endif /* CTK_SCREENSAVER_RUN */
adamdunkels66109622003-04-24 17:17:10 +00001051#endif /* 0 */
adamdunkelsb2486562003-04-11 20:22:03 +00001052 if(ctk_arch_keyavail()
1053#if CTK_CONF_MOUSE_SUPPORT
1054 || mouse_moved || mouse_button_changed
1055#endif /* CTK_CONF_MOUSE_SUPPORT */
1056 ) {
adamdunkels66109622003-04-24 17:17:10 +00001057 dispatcher_emit(ctk_signal_screensaver_stop, NULL, DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001058 mode = CTK_MODE_NORMAL;
adamdunkels66109622003-04-24 17:17:10 +00001059 /* ctk_draw_init();
1060 ctk_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001061 }
adamdunkels66109622003-04-24 17:17:10 +00001062 } else
1063#endif /* CTK_CONF_SCREENSAVER */
1064 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001065#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001066 /* If there is any change in the mouse conditions, find out in
1067 which window the mouse pointer currently is in order to send
1068 the correct signals, or bring a window to focus. */
1069 if(mouse_moved || mouse_button_changed) {
1070 ctk_mouse_show();
1071 screensaver_timer = 0;
1072
1073 if(myc == 0) {
1074 /* Here we should do whatever needs to be done when the mouse
1075 moves around and clicks in the menubar. */
1076 if(mouse_clicked) {
1077 /* Find out which menu that the mouse pointer is in. Start
1078 with the ->next menu after the desktop menu. We assume
1079 that the menus start one character from the left screen
1080 side and that the desktop menu is farthest to the
1081 right. */
1082 menux = 1;
1083 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1084 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1085 break;
adamdunkelse0683312003-04-09 09:02:52 +00001086 }
adamdunkelsb2486562003-04-11 20:22:03 +00001087 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001088 }
adamdunkelsb2486562003-04-11 20:22:03 +00001089
1090 /* Also check desktop menu. */
1091 if(mxc >= width - 7 &&
1092 mxc <= width - 1) {
1093 menu = &desktopmenu;
1094 }
1095
1096 menus.open = menu;
1097 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001098 }
adamdunkelse0683312003-04-09 09:02:52 +00001099 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001100 --myc;
1101
1102 if(menus.open != NULL) {
1103 /* Do whatever needs to be done when a menu is open. */
1104
1105 if(menus.open == &desktopmenu) {
1106 menux = width - CTK_CONF_MENUWIDTH;
1107 } else {
1108 menux = 1;
1109 for(menu = menus.menus->next; menu != menus.open;
1110 menu = menu->next) {
1111 menux += menu->titlelen;
1112 }
1113 }
1114
1115 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1116 menus.open->active = myc;
1117 }
1118
1119 if(mouse_clicked) {
1120 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1121 redraw |= activate_menu();
1122 } else {
1123 lastmenu = menus.open;
1124 menus.open = NULL;
1125 redraw |= REDRAW_MENUPART;
1126 }
1127 } else {
1128 redraw |= REDRAW_MENUS;
1129 }
1130 } else {
1131
1132 /* Walk through the windows from top to bottom to see in which
1133 window the mouse pointer is. */
1134 if(dialog != NULL) {
1135 window = dialog;
1136 } else {
1137 for(window = windows; window != NULL; window = window->next) {
1138 /* Check if the mouse is within the window. */
1139 if(mxc >= window->x &&
1140 mxc <= window->x + window->w &&
1141 myc >= window->y &&
1142 myc <= window->y + window->h) {
1143 break;
1144 }
1145 }
1146 }
1147
1148
1149 /* If we didn't find any window, and there are no windows
1150 open, the mouse pointer will definately be within the
1151 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001152 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001153 window = &desktop_window;
1154 }
1155
1156 /* If the mouse pointer moves around outside of the currently
1157 focused window (or dialog), we should not have any focused
1158 widgets in the focused window so we make sure that there
1159 are none. */
1160 if(windows != NULL &&
1161 window != windows &&
1162 windows->focused != NULL){
1163 add_redrawwidget(windows->focused);
1164 windows->focused = NULL;
1165 redraw |= REDRAW_WIDGETS;
1166 }
1167
1168 if(window != NULL) {
1169 /* If the mouse was clicked outside of the current window, we
1170 bring the clicked window to front. */
1171 if(dialog == NULL &&
1172 window != &desktop_window &&
1173 window != windows &&
1174 mouse_clicked) {
1175 /* Bring window to front. */
1176 ctk_window_open(window);
1177 redraw |= REDRAW_ALL;
1178 } else {
1179
1180 /* Find out which widget currently is under the mouse pointer
1181 and give it focus, unless it already has focus. */
1182 mxc = mxc - window->x - 1;
1183 myc = myc - window->y - 1;
1184
1185 /* See if the mouse pointer is on a widget. If so, it should be
1186 selected and, if the button is clicked, activated. */
1187 for(widget = window->active; widget != NULL;
1188 widget = widget->next) {
1189 if(mxc >= widget->x &&
1190 mxc <= widget->x + widget->w &&
1191 (myc == widget->y ||
1192 ((widget->type == CTK_WIDGET_BITMAP ||
1193 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1194 widget->type == CTK_WIDGET_ICON) &&
1195 (myc >= widget->y &&
1196 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1197 break;
1198 }
1199 }
1200
1201
adamdunkels58917a82003-04-18 00:18:38 +00001202 if(mouse_moved &&
1203 (window != &desktop_window ||
1204 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001205 dispatcher_emit(ctk_signal_pointer_move, NULL,
1206 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001207
adamdunkelsb2486562003-04-11 20:22:03 +00001208 if(window->focused != NULL &&
1209 widget != window->focused) {
1210 add_redrawwidget(window->focused);
1211 if(CTK_WIDGET_TYPE(window->focused) ==
1212 CTK_WIDGET_TEXTENTRY) {
1213 ((struct ctk_textentry *)(window->focused))->state =
1214 CTK_TEXTENTRY_NORMAL;
1215 }
1216 window->focused = NULL;
1217 }
1218 redraw |= REDRAW_WIDGETS;
1219 if(widget != NULL) {
1220 select_widget(widget);
1221 }
1222 }
1223
1224 if(mouse_button_changed) {
1225 dispatcher_emit(ctk_signal_pointer_button,
1226 (ek_data_t)mouse_button,
1227 window->owner);
1228 if(mouse_clicked && widget != NULL) {
1229 select_widget(widget);
1230 redraw |= activate(widget);
1231 }
1232 }
1233 }
1234 }
1235 }
adamdunkelsc4902862003-04-09 00:30:45 +00001236 }
1237 }
adamdunkels19a787c2003-04-09 09:22:24 +00001238#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001239
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001240 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001241
1242 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001243
1244 screensaver_timer = 0;
1245
adamdunkelsb2486562003-04-11 20:22:03 +00001246 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001247
1248 if(dialog != NULL) {
1249 window = dialog;
1250 } else if(windows != NULL) {
1251 window = windows;
1252 } else {
1253 window = &desktop_window;
1254 }
1255 widget = window->focused;
1256
1257
1258 if(widget != NULL &&
1259 widget->type == CTK_WIDGET_TEXTENTRY &&
1260 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1261 textentry_input(c, (struct ctk_textentry *)widget);
1262 add_redrawwidget(widget);
1263#if CTK_CONF_MENUS
1264 } else if(menus.open != NULL) {
1265 redraw |= menus_input(c);
1266#endif /* CTK_CONF_MENUS */
1267 } else {
1268 switch(c) {
1269 case CH_CURS_RIGHT:
1270 switch_focus_widget(RIGHT);
1271 break;
1272 case CH_CURS_DOWN:
1273 switch_focus_widget(DOWN);
1274 break;
1275 case CH_CURS_LEFT:
1276 switch_focus_widget(LEFT);
1277 break;
1278 case CH_CURS_UP:
1279 switch_focus_widget(UP);
1280 break;
1281 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001282 if(widget != NULL) {
1283 redraw |= activate(widget);
1284 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001285 break;
1286#if CTK_CONF_MENUS
1287 case CTK_CONF_MENU_KEY:
1288 if(dialog == NULL) {
1289 if(lastmenu == NULL) {
1290 menus.open = menus.menus;
1291 } else {
1292 menus.open = lastmenu;
1293 }
1294 menus.open->active = 0;
1295 redraw |= REDRAW_MENUS;
1296 }
1297 break;
1298#endif /* CTK_CONF_MENUS */
1299 case CTK_CONF_WINDOWSWITCH_KEY:
1300 if(windows != NULL) {
1301 for(window = windows; window->next != NULL;
1302 window = window->next);
1303 ctk_window_open(window);
1304 ctk_redraw();
1305 }
1306 break;
1307 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001308 if(widget != NULL &&
1309 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001310 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1311 textentry_input(c, (struct ctk_textentry *)widget);
1312 add_redrawwidget(widget);
1313 } else {
1314 dispatcher_emit(ctk_signal_keypress, (void *)c,
1315 window->owner);
1316 }
1317 break;
1318 }
1319 }
1320
1321 if(redraw & REDRAW_WIDGETS) {
1322 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001323 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001324 }
1325 redraw &= ~REDRAW_WIDGETS;
1326 redraw_widgetptr = 0;
1327 }
1328 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001329#if CTK_CONF_WINDOWMOVE
1330 } else if(mode == CTK_MODE_WINDOWMOVE) {
1331
1332 redraw = 0;
1333
1334 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001335
1336#if CTK_CONF_MOUSE_SUPPORT
1337
1338 /* If the mouse has moved, we move the window as well. */
1339 if(mouse_moved) {
1340
1341 if(window->w + mxc + 2 >= width) {
1342 window->x = width - 2 - window->w;
1343 } else {
1344 window->x = mxc;
1345 }
1346
1347 if(window->h + myc + 2 >= height) {
1348 window->y = height - 2 - window->h;
1349 } else {
1350 window->y = myc;
1351 }
1352 if(window->y > 0) {
1353 --window->y;
1354 }
1355
1356 redraw = REDRAW_ALL;
1357 }
1358
1359 /* Check if the mouse has been clicked, and stop moving the window
1360 if so. */
1361 if(mouse_button_changed &&
1362 mouse_button == 0) {
1363 mode = CTK_MODE_NORMAL;
1364 redraw = REDRAW_ALL;
1365 }
1366#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001367
1368 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1369
1370 screensaver_timer = 0;
1371
1372 c = ctk_arch_getkey();
1373
1374 switch(c) {
1375 case CH_CURS_RIGHT:
1376 ++window->x;
1377 if(window->x + window->w + 1 >= width) {
1378 --window->x;
1379 }
1380 redraw = REDRAW_ALL;
1381 break;
1382 case CH_CURS_LEFT:
1383 if(window->x > 0) {
1384 --window->x;
1385 }
1386 redraw = REDRAW_ALL;
1387 break;
1388 case CH_CURS_DOWN:
1389 ++window->y;
1390 if(window->y + window->h + 2 >= height) {
1391 --window->y;
1392 }
1393 redraw = REDRAW_ALL;
1394 break;
1395 case CH_CURS_UP:
1396 if(window->y > 0) {
1397 --window->y;
1398 }
1399 redraw = REDRAW_ALL;
1400 break;
1401 case CH_ENTER:
1402 case CH_ESC:
1403 mode = CTK_MODE_NORMAL;
1404 redraw = REDRAW_ALL;
1405 break;
1406 }
1407 }
adamdunkelsb2486562003-04-11 20:22:03 +00001408 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001409 do_redraw_all(1, height);
1410 }
adamdunkelsb2486562003-04-11 20:22:03 +00001411 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001412#endif /* CTK_CONF_WINDOWMOVE */
1413 }
adamdunkelsb2486562003-04-11 20:22:03 +00001414
1415 if(redraw & REDRAW_ALL) {
1416 do_redraw_all(1, height);
1417#if CTK_CONF_MENUS
1418 } else if(redraw & REDRAW_MENUPART) {
1419 do_redraw_all(1, maxnitems + 1);
1420 } else if(redraw & REDRAW_MENUS) {
1421 ctk_draw_menus(&menus);
1422#endif /* CTK_CONF_MENUS */
1423 } else if(redraw & REDRAW_FOCUS) {
1424 if(dialog != NULL) {
1425 ctk_window_redraw(dialog);
1426 } else if(windows != NULL) {
1427 ctk_window_redraw(windows);
1428 } else {
1429 ctk_window_redraw(&desktop_window);
1430 }
1431 } else if(redraw & REDRAW_WIDGETS) {
1432 for(i = 0; i < redraw_widgetptr; ++i) {
1433 ctk_widget_redraw(redraw_widgets[i]);
1434 }
1435 }
1436 redraw = 0;
1437 redraw_widgetptr = 0;
1438
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001439}
1440/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001441static
1442DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001443{
adamdunkels78c03dc2003-04-09 13:45:05 +00001444 DISPATCHER_SIGHANDLER_ARGS(s, data);
1445
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001446 if(s == ctk_signal_timer) {
1447 if(mode == CTK_MODE_NORMAL) {
1448 ++screensaver_timer;
1449 if(screensaver_timer == SCREENSAVER_TIMEOUT) {
adamdunkels66109622003-04-24 17:17:10 +00001450#if CTK_CONF_SCREENSAVER
1451 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1452 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001453#ifdef CTK_SCREENSAVER_INIT
1454 CTK_SCREENSAVER_INIT();
1455#endif /* CTK_SCREENSAVER_INIT */
1456 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001457#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001458 screensaver_timer = 0;
1459 }
1460 }
1461 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1462 }
1463}
1464/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001465