blob: bf28a80bb22f2800a51395b630bda2f03e3ee3f5 [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 *
adamdunkelse2f4d2a2003-04-28 23:21:42 +000035 * $Id: ctk.c,v 1.18 2003/04/28 23:21:42 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;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000117unsigned short ctk_screensaver_timeout = (5*60);
118/*#define SCREENSAVER_TIMEOUT (5*60)*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000119
120#if CTK_CONF_MENUS
121/*-----------------------------------------------------------------------------------*/
122/* make_desktopmenu(void)
123 *
124 * Creates the leftmost menu, "Desktop". Since the desktop menu
125 * contains the list of all open windows, this function will be called
126 * whenever a window is opened or closed.
127 */
128static void
129make_desktopmenu(void)
130{
131 struct ctk_window *w;
132
133 desktopmenu.nitems = 0;
134
135 if(windows == NULL) {
136 ctk_menuitem_add(&desktopmenu, "(No windows)");
137 } else {
138 for(w = windows; w != NULL; w = w->next) {
139 ctk_menuitem_add(&desktopmenu, w->title);
140 }
141 }
142}
143#endif /* CTK_CONF_MENUS */
144/*-----------------------------------------------------------------------------------*/
145/* ctk_init(void)
146 *
147 * Initializes CTK. Must be called before any other CTK function.
148 */
149void
150ctk_init(void)
151{
152 ctkid = dispatcher_start(&p);
153
154 windows = NULL;
155 dialog = NULL;
156
157#if CTK_CONF_MENUS
158 ctk_menu_new(&desktopmenu, "Desktop");
159 make_desktopmenu();
160 menus.menus = menus.desktopmenu = &desktopmenu;
161#endif /* CTK_CONF_MENUS */
162
adamdunkelsb2486562003-04-11 20:22:03 +0000163#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000164 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000165 ctk_mouse_show();
166#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000167
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000168 ctk_draw_init();
169
170 height = ctk_draw_height();
171 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000172
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000173 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000174
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000175 ctk_signal_keypress = dispatcher_sigalloc();
176 ctk_signal_timer = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000177
178 ctk_signal_button_activate =
179 ctk_signal_widget_activate = dispatcher_sigalloc();
180
181 ctk_signal_button_hover =
182 ctk_signal_hyperlink_hover =
183 ctk_signal_widget_select = dispatcher_sigalloc();
184
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000185 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000186
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000187 ctk_signal_menu_activate = dispatcher_sigalloc();
188 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000189
190 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000191 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000192
193
194#if CTK_CONF_SCREENSAVER
195 ctk_signal_screensaver_start = dispatcher_sigalloc();
196 ctk_signal_screensaver_stop = dispatcher_sigalloc();
197 ctk_signal_screensaver_uninstall = dispatcher_sigalloc();
198#endif /* CTK_CONF_SCREENSAVER */
199
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000200 dispatcher_listen(ctk_signal_timer);
201 dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
202
203 mode = CTK_MODE_NORMAL;
204
205 iconx = ICONX_START;
206 icony = ICONY_START;
207
208}
209/*-----------------------------------------------------------------------------------*/
210/* void ctk_mode_set()
211 */
212void
213ctk_mode_set(unsigned char m) {
214 mode = m;
215}
216/*-----------------------------------------------------------------------------------*/
217unsigned char
218ctk_mode_get(void) {
219 return mode;
220}
221/*-----------------------------------------------------------------------------------*/
222void
adamdunkelsd07a5422003-04-05 12:22:35 +0000223ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000224 ek_id_t id)
225{
226#if CTK_CONF_ICONS
227 icon->x = iconx;
228 icon->y = icony;
229 icon->widget.icon.owner = id;
230
231 icony += ICONY_DELTA;
232 if(icony >= ICONY_MAX) {
233 icony = ICONY_START;
234 iconx += ICONX_DELTA;
235 }
236
237 ctk_widget_add(&desktop_window, icon);
238#endif /* CTK_CONF_ICONS */
239}
240/*-----------------------------------------------------------------------------------*/
241void
242ctk_dialog_open(struct ctk_window *d)
243{
244 dialog = d;
245}
246/*-----------------------------------------------------------------------------------*/
247void
248ctk_dialog_close(void)
249{
250 dialog = NULL;
251}
252/*-----------------------------------------------------------------------------------*/
253void
adamdunkelsd07a5422003-04-05 12:22:35 +0000254ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255{
256 struct ctk_window *w2;
257
258 /* Check if already open. */
259 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
260 if(w2 == NULL) {
261 /* Not open, so we add it at the head of the list of open
262 windows. */
263 w->next = windows;
264 if(windows != NULL) {
265 windows->prev = w;
266 }
267 windows = w;
268 w->prev = NULL;
269 } else {
270 /* Window already open, so we move it to the front of the windows
271 list. */
272 if(w != windows) {
273 if(w->next != NULL) {
274 w->next->prev = w->prev;
275 }
276 if(w->prev != NULL) {
277 w->prev->next = w->next;
278 }
279 w->next = windows;
280 windows->prev = w;
281 windows = w;
282 w->prev = NULL;
283 }
284 }
285
286#if CTK_CONF_MENUS
287 /* Recreate the Desktop menu's window entries.*/
288 make_desktopmenu();
289#endif /* CTK_CONF_MENUS */
290}
291/*-----------------------------------------------------------------------------------*/
292void
293ctk_window_close(struct ctk_window *w)
294{
295 struct ctk_window *w2;
296
297 if(w == NULL) {
298 return;
299 }
300
301 /* Check if the window to be closed is the first window on the
302 list. */
303 if(w == windows) {
304 windows = w->next;
305 if(windows != NULL) {
306 windows->prev = NULL;
307 }
308 w->next = w->prev = NULL;
309 } else {
310 /* Otherwise we step through the list until we find the window
311 before the one to be closed. We then redirect its ->next
312 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000313 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
314
315 if(w2 == NULL) {
316 /* The window wasn't open, so there is nothing more for us to
317 do. */
318 return;
319 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000320
321 if(w->next != NULL) {
322 w->next->prev = w->prev;
323 }
324 w2->next = w->next;
325
326 w->next = w->prev = NULL;
327 }
328
329#if CTK_CONF_MENUS
330 /* Recreate the Desktop menu's window entries.*/
331 make_desktopmenu();
332#endif /* CTK_CONF_MENUS */
333}
334/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000335static void
336make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000337{
338#if CTK_CONF_WINDOWMOVE
339 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
340#else
341 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
342#endif /* CTK_CONF_WINDOWMOVE */
343 CTK_WIDGET_ADD(window, &window->titlebutton);
344
345
346#if CTK_CONF_WINDOWCLOSE
347 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
348#else
349 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
350#endif /* CTK_CONF_WINDOWCLOSE */
351 CTK_WIDGET_ADD(window, &window->closebutton);
352}
353/*-----------------------------------------------------------------------------------*/
354void
355ctk_window_clear(struct ctk_window *window)
356{
357 window->active = window->inactive = window->focused = NULL;
358
359 make_windowbuttons(window);
360}
361/*-----------------------------------------------------------------------------------*/
362void
363ctk_menu_add(struct ctk_menu *menu)
364{
365#if CTK_CONF_MENUS
366 struct ctk_menu *m;
367
368 if(lastmenu == NULL) {
369 lastmenu = menu;
370 }
371
372 for(m = menus.menus; m->next != NULL; m = m->next) {
373 if(m == menu) {
374 return;
375 }
376 }
377 m->next = menu;
378 menu->next = NULL;
379#endif /* CTK_CONF_MENUS */
380}
381/*-----------------------------------------------------------------------------------*/
382void
383ctk_menu_remove(struct ctk_menu *menu)
384{
385#if CTK_CONF_MENUS
386 struct ctk_menu *m;
387
388 for(m = menus.menus; m->next != NULL; m = m->next) {
389 if(m->next == menu) {
390 m->next = menu->next;
391 return;
392 }
393 }
394#endif /* CTK_CONF_MENUS */
395}
396/*-----------------------------------------------------------------------------------*/
397static void
398do_redraw_all(unsigned char clipy1, unsigned char clipy2)
399{
400 struct ctk_window *w;
401 struct ctk_widget *widget;
402
403 if(mode != CTK_MODE_NORMAL &&
404 mode != CTK_MODE_WINDOWMOVE) {
405 return;
406 }
407
408 ctk_draw_clear(clipy1, clipy2);
409
410 /* Draw widgets in root window */
411 for(widget = desktop_window.active;
412 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000413 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000414 }
415
416 /* Draw windows */
417 if(windows != NULL) {
418 /* Find the last window.*/
419 for(w = windows; w->next != NULL; w = w->next);
420
421 /* Draw the windows from back to front. */
422 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000423 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000424 ctk_draw_window(w, 0, clipy1, clipy2);
425 }
426 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000427 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000428 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
429 }
430
431 /* Draw dialog (if any) */
432 if(dialog != NULL) {
433 ctk_draw_dialog(dialog);
434 }
435
436#if CTK_CONF_MENUS
437 ctk_draw_menus(&menus);
438#endif /* CTK_CONF_MENUS */
439}
440/*-----------------------------------------------------------------------------------*/
441void
442ctk_redraw(void)
443{
444 if(DISPATCHER_CURRENT() == ctkid) {
445 if(mode == CTK_MODE_NORMAL ||
446 mode == CTK_MODE_WINDOWMOVE) {
447 do_redraw_all(1, height);
448 }
449 } else {
450 redraw |= REDRAW_ALL;
451 }
452}
453/*-----------------------------------------------------------------------------------*/
454void
455ctk_window_redraw(struct ctk_window *w)
456{
457 /* Only redraw the window if it is a dialog or if it is the foremost
458 window. */
459 if(mode != CTK_MODE_NORMAL) {
460 return;
461 }
462
463 if(w == dialog) {
464 ctk_draw_dialog(w);
465 } else if(dialog == NULL &&
466#if CTK_CONF_MENUS
467 menus.open == NULL &&
468#endif /* CTK_CONF_MENUS */
469 windows == w) {
470 ctk_draw_window(w, CTK_FOCUS_WINDOW,
471 0, height);
472 }
473}
474/*-----------------------------------------------------------------------------------*/
475static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000476window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000477 unsigned char w, unsigned char h,
478 char *title)
479{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000480
481 if(w >= width - 2) {
482 window->x = 0;
483 } else {
484 window->x = (width - w - 2) / 2;
485 }
486 if(h >= height - 3) {
487 window->y = 0;
488 } else {
489 window->y = (height - h - 1) / 2;
490 }
491
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000492 window->w = w;
493 window->h = h;
494 window->title = title;
495 if(title != NULL) {
496 window->titlelen = strlen(title);
497 } else {
498 window->titlelen = 0;
499 }
500 window->next = window->prev = NULL;
501 window->owner = DISPATCHER_CURRENT();
502 window->active = window->inactive = window->focused = NULL;
503}
504/*-----------------------------------------------------------------------------------*/
505void
506ctk_window_new(struct ctk_window *window,
507 unsigned char w, unsigned char h,
508 char *title)
509{
510 window_new(window, w, h, title);
511
512 make_windowbuttons(window);
513}
514/*-----------------------------------------------------------------------------------*/
515void
adamdunkelsd07a5422003-04-05 12:22:35 +0000516ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000517 unsigned char w, unsigned char h)
518{
519 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000520}
521/*-----------------------------------------------------------------------------------*/
522void
adamdunkelsd07a5422003-04-05 12:22:35 +0000523ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000524 char *title)
525{
526#if CTK_CONF_MENUS
527 menu->next = NULL;
528 menu->title = title;
529 menu->titlelen = strlen(title);
530 menu->active = 0;
531 menu->nitems = 0;
532#endif /* CTK_CONF_MENUS */
533}
534/*-----------------------------------------------------------------------------------*/
535unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000536ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000537 char *name)
538{
539#if CTK_CONF_MENUS
540 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
541 return 0;
542 }
543 menu->items[menu->nitems].title = name;
544 menu->items[menu->nitems].titlelen = strlen(name);
545 return menu->nitems++;
546#else
547 return 0;
548#endif /* CTK_CONF_MENUS */
549}
550/*-----------------------------------------------------------------------------------*/
551static void
552add_redrawwidget(struct ctk_widget *w)
553{
554 static unsigned char i;
555
556 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
557 redraw |= REDRAW_FOCUS;
558 } else {
559 redraw |= REDRAW_WIDGETS;
560 /* Check if it is in the queue already. If so, we don't add it
561 again. */
562 for(i = 0; i < redraw_widgetptr; ++i) {
563 if(redraw_widgets[i] == w) {
564 return;
565 }
566 }
567 redraw_widgets[redraw_widgetptr++] = w;
568 }
569}
570/*-----------------------------------------------------------------------------------*/
571void
572ctk_widget_redraw(struct ctk_widget *widget)
573{
574 struct ctk_window *window;
575
adamdunkels9f667f22003-04-16 18:29:19 +0000576 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000577 return;
578 }
579
580 /* If this function isn't called by CTK itself, we only queue the
581 redraw request. */
582 if(DISPATCHER_CURRENT() != ctkid) {
583 redraw |= REDRAW_WIDGETS;
584 add_redrawwidget(widget);
585 } else {
586
587 /* Only redraw widgets that are in the foremost window. If we
588 would allow redrawing widgets in non-focused windows, we would
589 have to redraw all the windows that cover the non-focused
590 window as well, which would lead to flickering.
591
592 Also, we avoid drawing any widgets when the menus are active.
593 */
594
595#if CTK_CONF_MENUS
596 if(menus.open == NULL)
597#endif /* CTK_CONF_MENUS */
598 {
599 window = widget->window;
600 if(window == dialog) {
601 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels66109622003-04-24 17:17:10 +0000602 } else if(window == windows ||
603 window == &desktop_window) {
604 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000605 }
606 }
607 }
608}
609/*-----------------------------------------------------------------------------------*/
610void
adamdunkelsd07a5422003-04-05 12:22:35 +0000611ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
612 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000613{
614 if(widget->type == CTK_WIDGET_LABEL ||
615 widget->type == CTK_WIDGET_SEPARATOR) {
616 widget->next = window->inactive;
617 window->inactive = widget;
618 widget->window = window;
619 } else {
620 widget->next = window->active;
621 window->active = widget;
622 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000623 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000624 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000625 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000626 }
627}
628/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000629unsigned char
630ctk_desktop_width(struct ctk_window *w)
631{
632 return ctk_draw_width();
633}
634/*-----------------------------------------------------------------------------------*/
635unsigned char
636ctk_desktop_height(struct ctk_window *w)
637{
638 return ctk_draw_height();
639}
640/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000641static void
adamdunkelsb2486562003-04-11 20:22:03 +0000642select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000643{
644 struct ctk_window *window;
645
646 window = focus->window;
647
648 if(focus != window->focused) {
649 window->focused = focus;
650 /* The operation changed the focus, so we emit a "hover" signal
651 for those widgets that support it. */
652
653 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
654 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
655 window->owner);
656 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
657 dispatcher_emit(ctk_signal_button_hover, window->focused,
658 window->owner);
659 }
660
661 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000662
663 dispatcher_emit(ctk_signal_widget_select, focus,
664 focus->window->owner);
665
adamdunkelse0683312003-04-09 09:02:52 +0000666 }
667
668}
669/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000670#define UP 0
671#define DOWN 1
672#define LEFT 2
673#define RIGHT 3
674static void
675switch_focus_widget(unsigned char direction)
676{
677 register struct ctk_window *window;
678 register struct ctk_widget *focus;
679 struct ctk_widget *widget;
680
681
682 if(dialog != NULL) {
683 window = dialog;
684 } else {
685 window = windows;
686 }
687
688 /* If there are no windows open, we move focus around between the
689 icons on the root window instead. */
690 if(window == NULL) {
691 window = &desktop_window;
692 }
693
694 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000695 if(focus == NULL) {
696 focus = window->active;
697 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000698 add_redrawwidget(focus);
699
700 if((direction & 1) == 0) {
701 /* Move focus "up" */
702 focus = focus->next;
703 } else {
704 /* Move focus "down" */
705 for(widget = window->active;
706 widget != NULL; widget = widget->next) {
707 if(widget->next == focus) {
708 break;
709 }
710 }
711 focus = widget;
712 if(focus == NULL) {
713 if(window->active != NULL) {
714 for(focus = window->active;
715 focus->next != NULL; focus = focus->next);
716 }
717 }
718 }
719 if(focus == NULL) {
720 focus = window->active;
721 }
adamdunkelse0683312003-04-09 09:02:52 +0000722
adamdunkelsb2486562003-04-11 20:22:03 +0000723 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000724}
725/*-----------------------------------------------------------------------------------*/
726#if CTK_CONF_MENUS
727static void
728switch_open_menu(unsigned char rightleft)
729{
730 struct ctk_menu *menu;
731
732 if(rightleft == 0) {
733 /* Move right */
734 for(menu = menus.menus; menu != NULL; menu = menu->next) {
735 if(menu->next == menus.open) {
736 break;
737 }
738 }
739 lastmenu = menus.open;
740 menus.open = menu;
741 if(menus.open == NULL) {
742 for(menu = menus.menus;
743 menu->next != NULL; menu = menu->next);
744 menus.open = menu;
745 }
746 } else {
747 /* Move to left */
748 lastmenu = menus.open;
749 menus.open = menus.open->next;
750 if(menus.open == NULL) {
751 menus.open = menus.menus;
752 }
753 }
754
adamdunkels66109622003-04-24 17:17:10 +0000755 menus.open->active = 0;
756
757 /* if(menus.open->nitems > maxnitems) {
758 maxnitems = menus.open->nitems;
759 }*/
760
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000761 /* ctk_redraw();*/
762}
763/*-----------------------------------------------------------------------------------*/
764static void
765switch_menu_item(unsigned char updown)
766{
767 register struct ctk_menu *m;
768
769 m = menus.open;
770
771 if(updown == 0) {
772 /* Move up */
773 if(m->active == 0) {
774 m->active = m->nitems - 1;
775 } else {
776 --m->active;
777 if(m->items[m->active].title[0] == '-') {
778 --m->active;
779 }
780 }
781 } else {
782 /* Move down */
783 if(m->active >= m->nitems - 1) {
784 m->active = 0;
785 } else {
786 ++m->active;
787 if(m->items[m->active].title[0] == '-') {
788 ++m->active;
789 }
790 }
791 }
792
793}
794#endif /* CTK_CONF_MENUS */
795/*-----------------------------------------------------------------------------------*/
796static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000797activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000798{
799 static unsigned char len;
800
801 if(w->type == CTK_WIDGET_BUTTON) {
802 if(w == (struct ctk_widget *)&windows->closebutton) {
803#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000804 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805 ctk_window_close(windows);
806 return REDRAW_ALL;
807#endif /* CTK_CONF_WINDOWCLOSE */
808 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
809#if CTK_CONF_WINDOWCLOSE
810 mode = CTK_MODE_WINDOWMOVE;
811#endif /* CTK_CONF_WINDOWCLOSE */
812 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000813 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000814 w->window->owner);
815 }
816#if CTK_CONF_ICONS
817 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000818 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000819 w->widget.icon.owner);
820#endif /* CTK_CONF_ICONS */
821 } else if(w->type == CTK_WIDGET_HYPERLINK) {
822 dispatcher_emit(ctk_signal_hyperlink_activate, w,
823 DISPATCHER_BROADCAST);
824 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
825 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
826 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
827 len = strlen(w->widget.textentry.text);
828 if(w->widget.textentry.xpos > len) {
829 w->widget.textentry.xpos = len;
830 }
831 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
832 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
833 }
834 add_redrawwidget(w);
835 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000836 } else {
837 dispatcher_emit(ctk_signal_widget_activate, w,
838 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000839 }
840 return REDRAW_NONE;
841}
842/*-----------------------------------------------------------------------------------*/
843static void
844textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000845 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000846{
847 static char *cptr, *cptr2;
848 static unsigned char len, txpos, typos, tlen;
849
850 txpos = t->xpos;
851 typos = t->ypos;
852 tlen = t->len;
853
854 cptr = &t->text[txpos + typos * tlen];
855
856 switch(c) {
857 case CH_CURS_LEFT:
858 if(txpos > 0) {
859 --txpos;
860 }
861 break;
862
863 case CH_CURS_RIGHT:
864 if(txpos < tlen &&
865 *cptr != 0) {
866 ++txpos;
867 }
868 break;
869
870 case CH_CURS_UP:
871#if CTK_CONF_TEXTENTRY_MULTILINE
872 if(t->h == 1) {
873 txpos = 0;
874 } else {
875 if(typos > 0) {
876 --typos;
877 } else {
878 t->state = CTK_TEXTENTRY_NORMAL;
879 }
880 }
881#else
882 txpos = 0;
883#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
884 break;
885
886 case CH_CURS_DOWN:
887#if CTK_CONF_TEXTENTRY_MULTILINE
888 if(t->h == 1) {
889 txpos = strlen(t->text);
890 } else {
891 if(typos < t->h - 1) {
892 ++typos;
893 } else {
894 t->state = CTK_TEXTENTRY_NORMAL;
895 }
896 }
897#else
898 txpos = strlen(t->text);
899#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
900 break;
901
902 case CH_ENTER:
903#if CTK_CONF_TEXTENTRY_MULTILINE
904 if(t->h == 1) {
905 t->state = CTK_TEXTENTRY_NORMAL;
906 } else {
907 if(typos < t->h - 1) {
908 ++typos;
909 txpos = 0;
910 } else {
911 t->state = CTK_TEXTENTRY_NORMAL;
912 }
913 }
914#else
915 t->state = CTK_TEXTENTRY_NORMAL;
916#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
917 break;
918
919 default:
920 len = tlen - txpos - 1;
921 if(c == CH_DEL) {
922 if(txpos > 0 && len > 0) {
923 strncpy(cptr - 1, cptr,
924 len);
925 *(cptr + len - 1) = 0;
926 --txpos;
927 }
928 } else {
929 if(len > 0) {
930 cptr2 = cptr + len - 1;
931 while(cptr2 + 1 > cptr) {
932 *(cptr2 + 1) = *cptr2;
933 --cptr2;
934 }
935
936 *cptr = c;
937 ++txpos;
938 }
939 }
940 break;
941 }
942
943 t->xpos = txpos;
944 t->ypos = typos;
945}
946/*-----------------------------------------------------------------------------------*/
947#if CTK_CONF_MENUS
948static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000949activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000950{
951 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000952
953 lastmenu = menus.open;
954 if(menus.open == &desktopmenu) {
955 for(w = windows; w != NULL; w = w->next) {
956 if(w->title == desktopmenu.items[desktopmenu.active].title) {
957 ctk_window_open(w);
958 menus.open = NULL;
959 return REDRAW_ALL;
960 }
961 }
962 } else {
963 dispatcher_emit(ctk_signal_menu_activate, menus.open,
964 DISPATCHER_BROADCAST);
965 }
966 menus.open = NULL;
967 return REDRAW_MENUPART;
968}
969/*-----------------------------------------------------------------------------------*/
970static unsigned char
971menus_input(ctk_arch_key_t c)
972{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000973
974 if(menus.open->nitems > maxnitems) {
975 maxnitems = menus.open->nitems;
976 }
977
978
979 switch(c) {
980 case CH_CURS_RIGHT:
981 switch_open_menu(1);
982
983 return REDRAW_MENUPART;
984
985 case CH_CURS_DOWN:
986 switch_menu_item(1);
987 return REDRAW_MENUS;
988
989 case CH_CURS_LEFT:
990 switch_open_menu(0);
991 return REDRAW_MENUPART;
992
993 case CH_CURS_UP:
994 switch_menu_item(0);
995 return REDRAW_MENUS;
996
997 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000998 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000999
adamdunkels88ed9c42003-03-28 12:10:09 +00001000 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001001 lastmenu = menus.open;
1002 menus.open = NULL;
1003 return REDRAW_MENUPART;
1004 }
adamdunkelsb2486562003-04-11 20:22:03 +00001005
1006 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001007}
1008#endif /* CTK_CONF_MENUS */
1009/*-----------------------------------------------------------------------------------*/
1010static void
adamdunkelsc4902862003-04-09 00:30:45 +00001011ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001012{
1013 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001014 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001015 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001016 register struct ctk_widget *widget;
1017#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001018 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1019 mouse_clicked;
1020 static unsigned char menux;
1021 struct ctk_menu *menu;
1022
adamdunkels19a787c2003-04-09 09:22:24 +00001023#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001024
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001025#if CTK_CONF_MENUS
1026 if(menus.open != NULL) {
1027 maxnitems = menus.open->nitems;
1028 } else {
1029 maxnitems = 0;
1030 }
1031#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001032
1033#if CTK_CONF_MOUSE_SUPPORT
1034 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1035
1036 /* See if there is any change in the buttons. */
1037 if(ctk_mouse_button() != mouse_button) {
1038 mouse_button = ctk_mouse_button();
1039 mouse_button_changed = 1;
1040 if(mouse_button == 0) {
1041 mouse_clicked = 1;
1042 }
1043 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001044
adamdunkelsb2486562003-04-11 20:22:03 +00001045 /* Check if the mouse pointer has moved. */
1046 if(ctk_mouse_x() != mouse_x ||
1047 ctk_mouse_y() != mouse_y) {
1048 mouse_x = ctk_mouse_x();
1049 mouse_y = ctk_mouse_y();
1050 mouse_moved = 1;
1051 }
1052
1053 mxc = ctk_mouse_xtoc(mouse_x);
1054 myc = ctk_mouse_ytoc(mouse_y);
1055#endif /* CTK_CONF_MOUSE_SUPPORT */
1056
1057
adamdunkels66109622003-04-24 17:17:10 +00001058#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001059 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkels66109622003-04-24 17:17:10 +00001060#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001061#ifdef CTK_SCREENSAVER_RUN
1062 CTK_SCREENSAVER_RUN();
1063#endif /* CTK_SCREENSAVER_RUN */
adamdunkels66109622003-04-24 17:17:10 +00001064#endif /* 0 */
adamdunkelsb2486562003-04-11 20:22:03 +00001065 if(ctk_arch_keyavail()
1066#if CTK_CONF_MOUSE_SUPPORT
1067 || mouse_moved || mouse_button_changed
1068#endif /* CTK_CONF_MOUSE_SUPPORT */
1069 ) {
adamdunkels66109622003-04-24 17:17:10 +00001070 dispatcher_emit(ctk_signal_screensaver_stop, NULL, DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001071 mode = CTK_MODE_NORMAL;
adamdunkels66109622003-04-24 17:17:10 +00001072 /* ctk_draw_init();
1073 ctk_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001074 }
adamdunkels66109622003-04-24 17:17:10 +00001075 } else
1076#endif /* CTK_CONF_SCREENSAVER */
1077 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001078#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001079 /* If there is any change in the mouse conditions, find out in
1080 which window the mouse pointer currently is in order to send
1081 the correct signals, or bring a window to focus. */
1082 if(mouse_moved || mouse_button_changed) {
1083 ctk_mouse_show();
1084 screensaver_timer = 0;
1085
1086 if(myc == 0) {
1087 /* Here we should do whatever needs to be done when the mouse
1088 moves around and clicks in the menubar. */
1089 if(mouse_clicked) {
1090 /* Find out which menu that the mouse pointer is in. Start
1091 with the ->next menu after the desktop menu. We assume
1092 that the menus start one character from the left screen
1093 side and that the desktop menu is farthest to the
1094 right. */
1095 menux = 1;
1096 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1097 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1098 break;
adamdunkelse0683312003-04-09 09:02:52 +00001099 }
adamdunkelsb2486562003-04-11 20:22:03 +00001100 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001101 }
adamdunkelsb2486562003-04-11 20:22:03 +00001102
1103 /* Also check desktop menu. */
1104 if(mxc >= width - 7 &&
1105 mxc <= width - 1) {
1106 menu = &desktopmenu;
1107 }
1108
1109 menus.open = menu;
1110 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001111 }
adamdunkelse0683312003-04-09 09:02:52 +00001112 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001113 --myc;
1114
1115 if(menus.open != NULL) {
1116 /* Do whatever needs to be done when a menu is open. */
1117
1118 if(menus.open == &desktopmenu) {
1119 menux = width - CTK_CONF_MENUWIDTH;
1120 } else {
1121 menux = 1;
1122 for(menu = menus.menus->next; menu != menus.open;
1123 menu = menu->next) {
1124 menux += menu->titlelen;
1125 }
1126 }
1127
1128 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1129 menus.open->active = myc;
1130 }
1131
1132 if(mouse_clicked) {
1133 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1134 redraw |= activate_menu();
1135 } else {
1136 lastmenu = menus.open;
1137 menus.open = NULL;
1138 redraw |= REDRAW_MENUPART;
1139 }
1140 } else {
1141 redraw |= REDRAW_MENUS;
1142 }
1143 } else {
1144
1145 /* Walk through the windows from top to bottom to see in which
1146 window the mouse pointer is. */
1147 if(dialog != NULL) {
1148 window = dialog;
1149 } else {
1150 for(window = windows; window != NULL; window = window->next) {
1151 /* Check if the mouse is within the window. */
1152 if(mxc >= window->x &&
1153 mxc <= window->x + window->w &&
1154 myc >= window->y &&
1155 myc <= window->y + window->h) {
1156 break;
1157 }
1158 }
1159 }
1160
1161
1162 /* If we didn't find any window, and there are no windows
1163 open, the mouse pointer will definately be within the
1164 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001165 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001166 window = &desktop_window;
1167 }
1168
1169 /* If the mouse pointer moves around outside of the currently
1170 focused window (or dialog), we should not have any focused
1171 widgets in the focused window so we make sure that there
1172 are none. */
1173 if(windows != NULL &&
1174 window != windows &&
1175 windows->focused != NULL){
1176 add_redrawwidget(windows->focused);
1177 windows->focused = NULL;
1178 redraw |= REDRAW_WIDGETS;
1179 }
1180
1181 if(window != NULL) {
1182 /* If the mouse was clicked outside of the current window, we
1183 bring the clicked window to front. */
1184 if(dialog == NULL &&
1185 window != &desktop_window &&
1186 window != windows &&
1187 mouse_clicked) {
1188 /* Bring window to front. */
1189 ctk_window_open(window);
1190 redraw |= REDRAW_ALL;
1191 } else {
1192
1193 /* Find out which widget currently is under the mouse pointer
1194 and give it focus, unless it already has focus. */
1195 mxc = mxc - window->x - 1;
1196 myc = myc - window->y - 1;
1197
1198 /* See if the mouse pointer is on a widget. If so, it should be
1199 selected and, if the button is clicked, activated. */
1200 for(widget = window->active; widget != NULL;
1201 widget = widget->next) {
1202 if(mxc >= widget->x &&
1203 mxc <= widget->x + widget->w &&
1204 (myc == widget->y ||
1205 ((widget->type == CTK_WIDGET_BITMAP ||
1206 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1207 widget->type == CTK_WIDGET_ICON) &&
1208 (myc >= widget->y &&
1209 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1210 break;
1211 }
1212 }
1213
1214
adamdunkels58917a82003-04-18 00:18:38 +00001215 if(mouse_moved &&
1216 (window != &desktop_window ||
1217 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001218 dispatcher_emit(ctk_signal_pointer_move, NULL,
1219 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001220
adamdunkelsb2486562003-04-11 20:22:03 +00001221 if(window->focused != NULL &&
1222 widget != window->focused) {
1223 add_redrawwidget(window->focused);
1224 if(CTK_WIDGET_TYPE(window->focused) ==
1225 CTK_WIDGET_TEXTENTRY) {
1226 ((struct ctk_textentry *)(window->focused))->state =
1227 CTK_TEXTENTRY_NORMAL;
1228 }
1229 window->focused = NULL;
1230 }
1231 redraw |= REDRAW_WIDGETS;
1232 if(widget != NULL) {
1233 select_widget(widget);
1234 }
1235 }
1236
1237 if(mouse_button_changed) {
1238 dispatcher_emit(ctk_signal_pointer_button,
1239 (ek_data_t)mouse_button,
1240 window->owner);
1241 if(mouse_clicked && widget != NULL) {
1242 select_widget(widget);
1243 redraw |= activate(widget);
1244 }
1245 }
1246 }
1247 }
1248 }
adamdunkelsc4902862003-04-09 00:30:45 +00001249 }
1250 }
adamdunkels19a787c2003-04-09 09:22:24 +00001251#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001252
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001253 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001254
1255 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001256
1257 screensaver_timer = 0;
1258
adamdunkelsb2486562003-04-11 20:22:03 +00001259 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001260
1261 if(dialog != NULL) {
1262 window = dialog;
1263 } else if(windows != NULL) {
1264 window = windows;
1265 } else {
1266 window = &desktop_window;
1267 }
1268 widget = window->focused;
1269
1270
1271 if(widget != NULL &&
1272 widget->type == CTK_WIDGET_TEXTENTRY &&
1273 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1274 textentry_input(c, (struct ctk_textentry *)widget);
1275 add_redrawwidget(widget);
1276#if CTK_CONF_MENUS
1277 } else if(menus.open != NULL) {
1278 redraw |= menus_input(c);
1279#endif /* CTK_CONF_MENUS */
1280 } else {
1281 switch(c) {
1282 case CH_CURS_RIGHT:
1283 switch_focus_widget(RIGHT);
1284 break;
1285 case CH_CURS_DOWN:
1286 switch_focus_widget(DOWN);
1287 break;
1288 case CH_CURS_LEFT:
1289 switch_focus_widget(LEFT);
1290 break;
1291 case CH_CURS_UP:
1292 switch_focus_widget(UP);
1293 break;
1294 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001295 if(widget != NULL) {
1296 redraw |= activate(widget);
1297 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001298 break;
1299#if CTK_CONF_MENUS
1300 case CTK_CONF_MENU_KEY:
1301 if(dialog == NULL) {
1302 if(lastmenu == NULL) {
1303 menus.open = menus.menus;
1304 } else {
1305 menus.open = lastmenu;
1306 }
1307 menus.open->active = 0;
1308 redraw |= REDRAW_MENUS;
1309 }
1310 break;
1311#endif /* CTK_CONF_MENUS */
1312 case CTK_CONF_WINDOWSWITCH_KEY:
1313 if(windows != NULL) {
1314 for(window = windows; window->next != NULL;
1315 window = window->next);
1316 ctk_window_open(window);
1317 ctk_redraw();
1318 }
1319 break;
1320 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001321 if(widget != NULL &&
1322 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001323 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1324 textentry_input(c, (struct ctk_textentry *)widget);
1325 add_redrawwidget(widget);
1326 } else {
1327 dispatcher_emit(ctk_signal_keypress, (void *)c,
1328 window->owner);
1329 }
1330 break;
1331 }
1332 }
1333
1334 if(redraw & REDRAW_WIDGETS) {
1335 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001336 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001337 }
1338 redraw &= ~REDRAW_WIDGETS;
1339 redraw_widgetptr = 0;
1340 }
1341 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001342#if CTK_CONF_WINDOWMOVE
1343 } else if(mode == CTK_MODE_WINDOWMOVE) {
1344
1345 redraw = 0;
1346
1347 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001348
1349#if CTK_CONF_MOUSE_SUPPORT
1350
1351 /* If the mouse has moved, we move the window as well. */
1352 if(mouse_moved) {
1353
1354 if(window->w + mxc + 2 >= width) {
1355 window->x = width - 2 - window->w;
1356 } else {
1357 window->x = mxc;
1358 }
1359
1360 if(window->h + myc + 2 >= height) {
1361 window->y = height - 2 - window->h;
1362 } else {
1363 window->y = myc;
1364 }
1365 if(window->y > 0) {
1366 --window->y;
1367 }
1368
1369 redraw = REDRAW_ALL;
1370 }
1371
1372 /* Check if the mouse has been clicked, and stop moving the window
1373 if so. */
1374 if(mouse_button_changed &&
1375 mouse_button == 0) {
1376 mode = CTK_MODE_NORMAL;
1377 redraw = REDRAW_ALL;
1378 }
1379#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001380
1381 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1382
1383 screensaver_timer = 0;
1384
1385 c = ctk_arch_getkey();
1386
1387 switch(c) {
1388 case CH_CURS_RIGHT:
1389 ++window->x;
1390 if(window->x + window->w + 1 >= width) {
1391 --window->x;
1392 }
1393 redraw = REDRAW_ALL;
1394 break;
1395 case CH_CURS_LEFT:
1396 if(window->x > 0) {
1397 --window->x;
1398 }
1399 redraw = REDRAW_ALL;
1400 break;
1401 case CH_CURS_DOWN:
1402 ++window->y;
1403 if(window->y + window->h + 2 >= height) {
1404 --window->y;
1405 }
1406 redraw = REDRAW_ALL;
1407 break;
1408 case CH_CURS_UP:
1409 if(window->y > 0) {
1410 --window->y;
1411 }
1412 redraw = REDRAW_ALL;
1413 break;
1414 case CH_ENTER:
1415 case CH_ESC:
1416 mode = CTK_MODE_NORMAL;
1417 redraw = REDRAW_ALL;
1418 break;
1419 }
1420 }
adamdunkelsb2486562003-04-11 20:22:03 +00001421 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001422 do_redraw_all(1, height);
1423 }
adamdunkelsb2486562003-04-11 20:22:03 +00001424 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001425#endif /* CTK_CONF_WINDOWMOVE */
1426 }
adamdunkelsb2486562003-04-11 20:22:03 +00001427
1428 if(redraw & REDRAW_ALL) {
1429 do_redraw_all(1, height);
1430#if CTK_CONF_MENUS
1431 } else if(redraw & REDRAW_MENUPART) {
1432 do_redraw_all(1, maxnitems + 1);
1433 } else if(redraw & REDRAW_MENUS) {
1434 ctk_draw_menus(&menus);
1435#endif /* CTK_CONF_MENUS */
1436 } else if(redraw & REDRAW_FOCUS) {
1437 if(dialog != NULL) {
1438 ctk_window_redraw(dialog);
1439 } else if(windows != NULL) {
1440 ctk_window_redraw(windows);
1441 } else {
1442 ctk_window_redraw(&desktop_window);
1443 }
1444 } else if(redraw & REDRAW_WIDGETS) {
1445 for(i = 0; i < redraw_widgetptr; ++i) {
1446 ctk_widget_redraw(redraw_widgets[i]);
1447 }
1448 }
1449 redraw = 0;
1450 redraw_widgetptr = 0;
1451
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001452}
1453/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001454static
1455DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001456{
adamdunkels78c03dc2003-04-09 13:45:05 +00001457 DISPATCHER_SIGHANDLER_ARGS(s, data);
1458
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001459 if(s == ctk_signal_timer) {
1460 if(mode == CTK_MODE_NORMAL) {
1461 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001462 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001463#if CTK_CONF_SCREENSAVER
1464 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1465 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001466#ifdef CTK_SCREENSAVER_INIT
1467 CTK_SCREENSAVER_INIT();
1468#endif /* CTK_SCREENSAVER_INIT */
1469 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001470#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001471 screensaver_timer = 0;
1472 }
1473 }
1474 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1475 }
1476}
1477/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001478