blob: 4d7c94e77e0aa6689c527dd1761ea1bd425d104b [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 *
adamdunkels965e2922003-06-30 20:44:57 +000035 * $Id: ctk.c,v 1.19 2003/06/30 20:44:57 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;
adamdunkels965e2922003-06-30 20:44:57 +0000207
208 redraw = REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000209}
210/*-----------------------------------------------------------------------------------*/
211/* void ctk_mode_set()
212 */
213void
214ctk_mode_set(unsigned char m) {
215 mode = m;
216}
217/*-----------------------------------------------------------------------------------*/
218unsigned char
219ctk_mode_get(void) {
220 return mode;
221}
222/*-----------------------------------------------------------------------------------*/
223void
adamdunkelsd07a5422003-04-05 12:22:35 +0000224ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000225 ek_id_t id)
226{
227#if CTK_CONF_ICONS
228 icon->x = iconx;
229 icon->y = icony;
230 icon->widget.icon.owner = id;
231
232 icony += ICONY_DELTA;
233 if(icony >= ICONY_MAX) {
234 icony = ICONY_START;
235 iconx += ICONX_DELTA;
236 }
237
238 ctk_widget_add(&desktop_window, icon);
239#endif /* CTK_CONF_ICONS */
240}
241/*-----------------------------------------------------------------------------------*/
242void
243ctk_dialog_open(struct ctk_window *d)
244{
245 dialog = d;
adamdunkels965e2922003-06-30 20:44:57 +0000246 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000247}
248/*-----------------------------------------------------------------------------------*/
249void
250ctk_dialog_close(void)
251{
252 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000253 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000254}
255/*-----------------------------------------------------------------------------------*/
256void
adamdunkelsd07a5422003-04-05 12:22:35 +0000257ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000258{
259 struct ctk_window *w2;
260
261 /* Check if already open. */
262 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
263 if(w2 == NULL) {
264 /* Not open, so we add it at the head of the list of open
265 windows. */
266 w->next = windows;
267 if(windows != NULL) {
268 windows->prev = w;
269 }
270 windows = w;
271 w->prev = NULL;
272 } else {
273 /* Window already open, so we move it to the front of the windows
274 list. */
275 if(w != windows) {
276 if(w->next != NULL) {
277 w->next->prev = w->prev;
278 }
279 if(w->prev != NULL) {
280 w->prev->next = w->next;
281 }
282 w->next = windows;
283 windows->prev = w;
284 windows = w;
285 w->prev = NULL;
286 }
287 }
288
289#if CTK_CONF_MENUS
290 /* Recreate the Desktop menu's window entries.*/
291 make_desktopmenu();
292#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000293
294 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000295}
296/*-----------------------------------------------------------------------------------*/
297void
298ctk_window_close(struct ctk_window *w)
299{
300 struct ctk_window *w2;
301
302 if(w == NULL) {
303 return;
304 }
305
306 /* Check if the window to be closed is the first window on the
307 list. */
308 if(w == windows) {
309 windows = w->next;
310 if(windows != NULL) {
311 windows->prev = NULL;
312 }
313 w->next = w->prev = NULL;
314 } else {
315 /* Otherwise we step through the list until we find the window
316 before the one to be closed. We then redirect its ->next
317 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000318 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
319
320 if(w2 == NULL) {
321 /* The window wasn't open, so there is nothing more for us to
322 do. */
323 return;
324 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000325
326 if(w->next != NULL) {
327 w->next->prev = w->prev;
328 }
329 w2->next = w->next;
330
331 w->next = w->prev = NULL;
332 }
333
334#if CTK_CONF_MENUS
335 /* Recreate the Desktop menu's window entries.*/
336 make_desktopmenu();
337#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000338 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000339}
340/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000341static void
342make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000343{
344#if CTK_CONF_WINDOWMOVE
345 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
346#else
347 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
348#endif /* CTK_CONF_WINDOWMOVE */
349 CTK_WIDGET_ADD(window, &window->titlebutton);
350
351
352#if CTK_CONF_WINDOWCLOSE
353 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
354#else
355 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
356#endif /* CTK_CONF_WINDOWCLOSE */
357 CTK_WIDGET_ADD(window, &window->closebutton);
358}
359/*-----------------------------------------------------------------------------------*/
360void
361ctk_window_clear(struct ctk_window *window)
362{
363 window->active = window->inactive = window->focused = NULL;
364
365 make_windowbuttons(window);
366}
367/*-----------------------------------------------------------------------------------*/
368void
369ctk_menu_add(struct ctk_menu *menu)
370{
371#if CTK_CONF_MENUS
372 struct ctk_menu *m;
373
374 if(lastmenu == NULL) {
375 lastmenu = menu;
376 }
377
378 for(m = menus.menus; m->next != NULL; m = m->next) {
379 if(m == menu) {
380 return;
381 }
382 }
383 m->next = menu;
384 menu->next = NULL;
385#endif /* CTK_CONF_MENUS */
386}
387/*-----------------------------------------------------------------------------------*/
388void
389ctk_menu_remove(struct ctk_menu *menu)
390{
391#if CTK_CONF_MENUS
392 struct ctk_menu *m;
393
394 for(m = menus.menus; m->next != NULL; m = m->next) {
395 if(m->next == menu) {
396 m->next = menu->next;
397 return;
398 }
399 }
400#endif /* CTK_CONF_MENUS */
401}
402/*-----------------------------------------------------------------------------------*/
403static void
404do_redraw_all(unsigned char clipy1, unsigned char clipy2)
405{
406 struct ctk_window *w;
407 struct ctk_widget *widget;
408
409 if(mode != CTK_MODE_NORMAL &&
410 mode != CTK_MODE_WINDOWMOVE) {
411 return;
412 }
413
414 ctk_draw_clear(clipy1, clipy2);
415
416 /* Draw widgets in root window */
417 for(widget = desktop_window.active;
418 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000419 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000420 }
421
422 /* Draw windows */
423 if(windows != NULL) {
424 /* Find the last window.*/
425 for(w = windows; w->next != NULL; w = w->next);
426
427 /* Draw the windows from back to front. */
428 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000429 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000430 ctk_draw_window(w, 0, clipy1, clipy2);
431 }
432 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000433 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000434 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
435 }
436
437 /* Draw dialog (if any) */
438 if(dialog != NULL) {
439 ctk_draw_dialog(dialog);
440 }
441
442#if CTK_CONF_MENUS
443 ctk_draw_menus(&menus);
444#endif /* CTK_CONF_MENUS */
445}
446/*-----------------------------------------------------------------------------------*/
447void
adamdunkels965e2922003-06-30 20:44:57 +0000448ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000449{
450 if(DISPATCHER_CURRENT() == ctkid) {
451 if(mode == CTK_MODE_NORMAL ||
452 mode == CTK_MODE_WINDOWMOVE) {
453 do_redraw_all(1, height);
454 }
455 } else {
456 redraw |= REDRAW_ALL;
457 }
458}
459/*-----------------------------------------------------------------------------------*/
460void
461ctk_window_redraw(struct ctk_window *w)
462{
463 /* Only redraw the window if it is a dialog or if it is the foremost
464 window. */
465 if(mode != CTK_MODE_NORMAL) {
466 return;
467 }
468
469 if(w == dialog) {
470 ctk_draw_dialog(w);
471 } else if(dialog == NULL &&
472#if CTK_CONF_MENUS
473 menus.open == NULL &&
474#endif /* CTK_CONF_MENUS */
475 windows == w) {
476 ctk_draw_window(w, CTK_FOCUS_WINDOW,
477 0, height);
478 }
479}
480/*-----------------------------------------------------------------------------------*/
481static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000482window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000483 unsigned char w, unsigned char h,
484 char *title)
485{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000486
487 if(w >= width - 2) {
488 window->x = 0;
489 } else {
490 window->x = (width - w - 2) / 2;
491 }
492 if(h >= height - 3) {
493 window->y = 0;
494 } else {
495 window->y = (height - h - 1) / 2;
496 }
497
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000498 window->w = w;
499 window->h = h;
500 window->title = title;
501 if(title != NULL) {
502 window->titlelen = strlen(title);
503 } else {
504 window->titlelen = 0;
505 }
506 window->next = window->prev = NULL;
507 window->owner = DISPATCHER_CURRENT();
508 window->active = window->inactive = window->focused = NULL;
509}
510/*-----------------------------------------------------------------------------------*/
511void
512ctk_window_new(struct ctk_window *window,
513 unsigned char w, unsigned char h,
514 char *title)
515{
516 window_new(window, w, h, title);
517
518 make_windowbuttons(window);
519}
520/*-----------------------------------------------------------------------------------*/
521void
adamdunkelsd07a5422003-04-05 12:22:35 +0000522ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000523 unsigned char w, unsigned char h)
524{
525 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526}
527/*-----------------------------------------------------------------------------------*/
528void
adamdunkelsd07a5422003-04-05 12:22:35 +0000529ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000530 char *title)
531{
532#if CTK_CONF_MENUS
533 menu->next = NULL;
534 menu->title = title;
535 menu->titlelen = strlen(title);
536 menu->active = 0;
537 menu->nitems = 0;
538#endif /* CTK_CONF_MENUS */
539}
540/*-----------------------------------------------------------------------------------*/
541unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000542ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000543 char *name)
544{
545#if CTK_CONF_MENUS
546 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
547 return 0;
548 }
549 menu->items[menu->nitems].title = name;
550 menu->items[menu->nitems].titlelen = strlen(name);
551 return menu->nitems++;
552#else
553 return 0;
554#endif /* CTK_CONF_MENUS */
555}
556/*-----------------------------------------------------------------------------------*/
557static void
558add_redrawwidget(struct ctk_widget *w)
559{
560 static unsigned char i;
561
562 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
563 redraw |= REDRAW_FOCUS;
564 } else {
565 redraw |= REDRAW_WIDGETS;
566 /* Check if it is in the queue already. If so, we don't add it
567 again. */
568 for(i = 0; i < redraw_widgetptr; ++i) {
569 if(redraw_widgets[i] == w) {
570 return;
571 }
572 }
573 redraw_widgets[redraw_widgetptr++] = w;
574 }
575}
576/*-----------------------------------------------------------------------------------*/
577void
578ctk_widget_redraw(struct ctk_widget *widget)
579{
580 struct ctk_window *window;
581
adamdunkels9f667f22003-04-16 18:29:19 +0000582 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000583 return;
584 }
585
586 /* If this function isn't called by CTK itself, we only queue the
587 redraw request. */
588 if(DISPATCHER_CURRENT() != ctkid) {
589 redraw |= REDRAW_WIDGETS;
590 add_redrawwidget(widget);
591 } else {
592
593 /* Only redraw widgets that are in the foremost window. If we
594 would allow redrawing widgets in non-focused windows, we would
595 have to redraw all the windows that cover the non-focused
596 window as well, which would lead to flickering.
597
598 Also, we avoid drawing any widgets when the menus are active.
599 */
600
601#if CTK_CONF_MENUS
602 if(menus.open == NULL)
603#endif /* CTK_CONF_MENUS */
604 {
605 window = widget->window;
606 if(window == dialog) {
607 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels66109622003-04-24 17:17:10 +0000608 } else if(window == windows ||
609 window == &desktop_window) {
610 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000611 }
612 }
613 }
614}
615/*-----------------------------------------------------------------------------------*/
616void
adamdunkelsd07a5422003-04-05 12:22:35 +0000617ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
618 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000619{
620 if(widget->type == CTK_WIDGET_LABEL ||
621 widget->type == CTK_WIDGET_SEPARATOR) {
622 widget->next = window->inactive;
623 window->inactive = widget;
624 widget->window = window;
625 } else {
626 widget->next = window->active;
627 window->active = widget;
628 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000629 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000630 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000631 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000632 }
633}
634/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000635unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000636ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000637{
638 return ctk_draw_width();
639}
640/*-----------------------------------------------------------------------------------*/
641unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000642ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000643{
644 return ctk_draw_height();
645}
646/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000647static void
adamdunkelsb2486562003-04-11 20:22:03 +0000648select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000649{
650 struct ctk_window *window;
651
652 window = focus->window;
653
654 if(focus != window->focused) {
655 window->focused = focus;
656 /* The operation changed the focus, so we emit a "hover" signal
657 for those widgets that support it. */
658
659 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
660 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
661 window->owner);
662 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
663 dispatcher_emit(ctk_signal_button_hover, window->focused,
664 window->owner);
665 }
666
667 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000668
669 dispatcher_emit(ctk_signal_widget_select, focus,
670 focus->window->owner);
671
adamdunkelse0683312003-04-09 09:02:52 +0000672 }
673
674}
675/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000676#define UP 0
677#define DOWN 1
678#define LEFT 2
679#define RIGHT 3
680static void
681switch_focus_widget(unsigned char direction)
682{
683 register struct ctk_window *window;
684 register struct ctk_widget *focus;
685 struct ctk_widget *widget;
686
687
688 if(dialog != NULL) {
689 window = dialog;
690 } else {
691 window = windows;
692 }
693
694 /* If there are no windows open, we move focus around between the
695 icons on the root window instead. */
696 if(window == NULL) {
697 window = &desktop_window;
698 }
699
700 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000701 if(focus == NULL) {
702 focus = window->active;
703 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000704 add_redrawwidget(focus);
705
706 if((direction & 1) == 0) {
707 /* Move focus "up" */
708 focus = focus->next;
709 } else {
710 /* Move focus "down" */
711 for(widget = window->active;
712 widget != NULL; widget = widget->next) {
713 if(widget->next == focus) {
714 break;
715 }
716 }
717 focus = widget;
718 if(focus == NULL) {
719 if(window->active != NULL) {
720 for(focus = window->active;
721 focus->next != NULL; focus = focus->next);
722 }
723 }
724 }
725 if(focus == NULL) {
726 focus = window->active;
727 }
adamdunkelse0683312003-04-09 09:02:52 +0000728
adamdunkelsb2486562003-04-11 20:22:03 +0000729 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000730}
731/*-----------------------------------------------------------------------------------*/
732#if CTK_CONF_MENUS
733static void
734switch_open_menu(unsigned char rightleft)
735{
736 struct ctk_menu *menu;
737
738 if(rightleft == 0) {
739 /* Move right */
740 for(menu = menus.menus; menu != NULL; menu = menu->next) {
741 if(menu->next == menus.open) {
742 break;
743 }
744 }
745 lastmenu = menus.open;
746 menus.open = menu;
747 if(menus.open == NULL) {
748 for(menu = menus.menus;
749 menu->next != NULL; menu = menu->next);
750 menus.open = menu;
751 }
752 } else {
753 /* Move to left */
754 lastmenu = menus.open;
755 menus.open = menus.open->next;
756 if(menus.open == NULL) {
757 menus.open = menus.menus;
758 }
759 }
760
adamdunkels66109622003-04-24 17:17:10 +0000761 menus.open->active = 0;
762
763 /* if(menus.open->nitems > maxnitems) {
764 maxnitems = menus.open->nitems;
765 }*/
766
adamdunkels965e2922003-06-30 20:44:57 +0000767 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000768}
769/*-----------------------------------------------------------------------------------*/
770static void
771switch_menu_item(unsigned char updown)
772{
773 register struct ctk_menu *m;
774
775 m = menus.open;
776
777 if(updown == 0) {
778 /* Move up */
779 if(m->active == 0) {
780 m->active = m->nitems - 1;
781 } else {
782 --m->active;
783 if(m->items[m->active].title[0] == '-') {
784 --m->active;
785 }
786 }
787 } else {
788 /* Move down */
789 if(m->active >= m->nitems - 1) {
790 m->active = 0;
791 } else {
792 ++m->active;
793 if(m->items[m->active].title[0] == '-') {
794 ++m->active;
795 }
796 }
797 }
798
799}
800#endif /* CTK_CONF_MENUS */
801/*-----------------------------------------------------------------------------------*/
802static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000803activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000804{
805 static unsigned char len;
806
807 if(w->type == CTK_WIDGET_BUTTON) {
808 if(w == (struct ctk_widget *)&windows->closebutton) {
809#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000810 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000811 ctk_window_close(windows);
812 return REDRAW_ALL;
813#endif /* CTK_CONF_WINDOWCLOSE */
814 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
815#if CTK_CONF_WINDOWCLOSE
816 mode = CTK_MODE_WINDOWMOVE;
817#endif /* CTK_CONF_WINDOWCLOSE */
818 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000819 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000820 w->window->owner);
821 }
822#if CTK_CONF_ICONS
823 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000824 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000825 w->widget.icon.owner);
826#endif /* CTK_CONF_ICONS */
827 } else if(w->type == CTK_WIDGET_HYPERLINK) {
828 dispatcher_emit(ctk_signal_hyperlink_activate, w,
829 DISPATCHER_BROADCAST);
830 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
831 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
832 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
833 len = strlen(w->widget.textentry.text);
834 if(w->widget.textentry.xpos > len) {
835 w->widget.textentry.xpos = len;
836 }
837 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
838 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
839 }
840 add_redrawwidget(w);
841 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000842 } else {
843 dispatcher_emit(ctk_signal_widget_activate, w,
844 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 }
846 return REDRAW_NONE;
847}
848/*-----------------------------------------------------------------------------------*/
849static void
850textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000851 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000852{
853 static char *cptr, *cptr2;
854 static unsigned char len, txpos, typos, tlen;
855
856 txpos = t->xpos;
857 typos = t->ypos;
858 tlen = t->len;
859
860 cptr = &t->text[txpos + typos * tlen];
861
862 switch(c) {
863 case CH_CURS_LEFT:
864 if(txpos > 0) {
865 --txpos;
866 }
867 break;
868
869 case CH_CURS_RIGHT:
870 if(txpos < tlen &&
871 *cptr != 0) {
872 ++txpos;
873 }
874 break;
875
876 case CH_CURS_UP:
877#if CTK_CONF_TEXTENTRY_MULTILINE
878 if(t->h == 1) {
879 txpos = 0;
880 } else {
881 if(typos > 0) {
882 --typos;
883 } else {
884 t->state = CTK_TEXTENTRY_NORMAL;
885 }
886 }
887#else
888 txpos = 0;
889#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
890 break;
891
892 case CH_CURS_DOWN:
893#if CTK_CONF_TEXTENTRY_MULTILINE
894 if(t->h == 1) {
895 txpos = strlen(t->text);
896 } else {
897 if(typos < t->h - 1) {
898 ++typos;
899 } else {
900 t->state = CTK_TEXTENTRY_NORMAL;
901 }
902 }
903#else
904 txpos = strlen(t->text);
905#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
906 break;
907
908 case CH_ENTER:
909#if CTK_CONF_TEXTENTRY_MULTILINE
910 if(t->h == 1) {
911 t->state = CTK_TEXTENTRY_NORMAL;
912 } else {
913 if(typos < t->h - 1) {
914 ++typos;
915 txpos = 0;
916 } else {
917 t->state = CTK_TEXTENTRY_NORMAL;
918 }
919 }
920#else
921 t->state = CTK_TEXTENTRY_NORMAL;
922#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
923 break;
924
925 default:
926 len = tlen - txpos - 1;
927 if(c == CH_DEL) {
928 if(txpos > 0 && len > 0) {
929 strncpy(cptr - 1, cptr,
930 len);
931 *(cptr + len - 1) = 0;
932 --txpos;
933 }
934 } else {
935 if(len > 0) {
936 cptr2 = cptr + len - 1;
937 while(cptr2 + 1 > cptr) {
938 *(cptr2 + 1) = *cptr2;
939 --cptr2;
940 }
941
942 *cptr = c;
943 ++txpos;
944 }
945 }
946 break;
947 }
948
949 t->xpos = txpos;
950 t->ypos = typos;
951}
952/*-----------------------------------------------------------------------------------*/
953#if CTK_CONF_MENUS
954static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000955activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000956{
957 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000958
959 lastmenu = menus.open;
960 if(menus.open == &desktopmenu) {
961 for(w = windows; w != NULL; w = w->next) {
962 if(w->title == desktopmenu.items[desktopmenu.active].title) {
963 ctk_window_open(w);
964 menus.open = NULL;
965 return REDRAW_ALL;
966 }
967 }
968 } else {
969 dispatcher_emit(ctk_signal_menu_activate, menus.open,
970 DISPATCHER_BROADCAST);
971 }
972 menus.open = NULL;
973 return REDRAW_MENUPART;
974}
975/*-----------------------------------------------------------------------------------*/
976static unsigned char
977menus_input(ctk_arch_key_t c)
978{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000979
980 if(menus.open->nitems > maxnitems) {
981 maxnitems = menus.open->nitems;
982 }
983
984
985 switch(c) {
986 case CH_CURS_RIGHT:
987 switch_open_menu(1);
988
989 return REDRAW_MENUPART;
990
991 case CH_CURS_DOWN:
992 switch_menu_item(1);
993 return REDRAW_MENUS;
994
995 case CH_CURS_LEFT:
996 switch_open_menu(0);
997 return REDRAW_MENUPART;
998
999 case CH_CURS_UP:
1000 switch_menu_item(0);
1001 return REDRAW_MENUS;
1002
1003 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001004 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001005
adamdunkels88ed9c42003-03-28 12:10:09 +00001006 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001007 lastmenu = menus.open;
1008 menus.open = NULL;
1009 return REDRAW_MENUPART;
1010 }
adamdunkelsb2486562003-04-11 20:22:03 +00001011
1012 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001013}
1014#endif /* CTK_CONF_MENUS */
1015/*-----------------------------------------------------------------------------------*/
1016static void
adamdunkelsc4902862003-04-09 00:30:45 +00001017ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001018{
1019 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001020 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001021 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001022 register struct ctk_widget *widget;
1023#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001024 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1025 mouse_clicked;
1026 static unsigned char menux;
1027 struct ctk_menu *menu;
1028
adamdunkels19a787c2003-04-09 09:22:24 +00001029#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001030
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001031#if CTK_CONF_MENUS
1032 if(menus.open != NULL) {
1033 maxnitems = menus.open->nitems;
1034 } else {
1035 maxnitems = 0;
1036 }
1037#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001038
1039#if CTK_CONF_MOUSE_SUPPORT
1040 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1041
1042 /* See if there is any change in the buttons. */
1043 if(ctk_mouse_button() != mouse_button) {
1044 mouse_button = ctk_mouse_button();
1045 mouse_button_changed = 1;
1046 if(mouse_button == 0) {
1047 mouse_clicked = 1;
1048 }
1049 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001050
adamdunkelsb2486562003-04-11 20:22:03 +00001051 /* Check if the mouse pointer has moved. */
1052 if(ctk_mouse_x() != mouse_x ||
1053 ctk_mouse_y() != mouse_y) {
1054 mouse_x = ctk_mouse_x();
1055 mouse_y = ctk_mouse_y();
1056 mouse_moved = 1;
1057 }
1058
1059 mxc = ctk_mouse_xtoc(mouse_x);
1060 myc = ctk_mouse_ytoc(mouse_y);
1061#endif /* CTK_CONF_MOUSE_SUPPORT */
1062
1063
adamdunkels66109622003-04-24 17:17:10 +00001064#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001065 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkels66109622003-04-24 17:17:10 +00001066#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001067#ifdef CTK_SCREENSAVER_RUN
1068 CTK_SCREENSAVER_RUN();
1069#endif /* CTK_SCREENSAVER_RUN */
adamdunkels66109622003-04-24 17:17:10 +00001070#endif /* 0 */
adamdunkelsb2486562003-04-11 20:22:03 +00001071 if(ctk_arch_keyavail()
1072#if CTK_CONF_MOUSE_SUPPORT
1073 || mouse_moved || mouse_button_changed
1074#endif /* CTK_CONF_MOUSE_SUPPORT */
1075 ) {
adamdunkels66109622003-04-24 17:17:10 +00001076 dispatcher_emit(ctk_signal_screensaver_stop, NULL, DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077 mode = CTK_MODE_NORMAL;
adamdunkels66109622003-04-24 17:17:10 +00001078 /* ctk_draw_init();
adamdunkels965e2922003-06-30 20:44:57 +00001079 ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001080 }
adamdunkels66109622003-04-24 17:17:10 +00001081 } else
1082#endif /* CTK_CONF_SCREENSAVER */
1083 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001084#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001085 /* If there is any change in the mouse conditions, find out in
1086 which window the mouse pointer currently is in order to send
1087 the correct signals, or bring a window to focus. */
1088 if(mouse_moved || mouse_button_changed) {
1089 ctk_mouse_show();
1090 screensaver_timer = 0;
1091
1092 if(myc == 0) {
1093 /* Here we should do whatever needs to be done when the mouse
1094 moves around and clicks in the menubar. */
1095 if(mouse_clicked) {
1096 /* Find out which menu that the mouse pointer is in. Start
1097 with the ->next menu after the desktop menu. We assume
1098 that the menus start one character from the left screen
1099 side and that the desktop menu is farthest to the
1100 right. */
1101 menux = 1;
1102 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1103 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1104 break;
adamdunkelse0683312003-04-09 09:02:52 +00001105 }
adamdunkelsb2486562003-04-11 20:22:03 +00001106 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001107 }
adamdunkelsb2486562003-04-11 20:22:03 +00001108
1109 /* Also check desktop menu. */
1110 if(mxc >= width - 7 &&
1111 mxc <= width - 1) {
1112 menu = &desktopmenu;
1113 }
1114
1115 menus.open = menu;
1116 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001117 }
adamdunkelse0683312003-04-09 09:02:52 +00001118 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001119 --myc;
1120
1121 if(menus.open != NULL) {
1122 /* Do whatever needs to be done when a menu is open. */
1123
1124 if(menus.open == &desktopmenu) {
1125 menux = width - CTK_CONF_MENUWIDTH;
1126 } else {
1127 menux = 1;
1128 for(menu = menus.menus->next; menu != menus.open;
1129 menu = menu->next) {
1130 menux += menu->titlelen;
1131 }
1132 }
1133
1134 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001135 if(myc <= menus.open->nitems) {
1136 menus.open->active = myc;
1137 } else {
1138 menus.open->active = menus.open->nitems - 1;
1139 }
adamdunkelsb2486562003-04-11 20:22:03 +00001140 }
1141
1142 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001143 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1144 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001145 redraw |= activate_menu();
1146 } else {
1147 lastmenu = menus.open;
1148 menus.open = NULL;
1149 redraw |= REDRAW_MENUPART;
1150 }
1151 } else {
1152 redraw |= REDRAW_MENUS;
1153 }
1154 } else {
1155
adamdunkels965e2922003-06-30 20:44:57 +00001156 /* Walk through the windows from top to bottom to see in
1157 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001158 if(dialog != NULL) {
1159 window = dialog;
1160 } else {
1161 for(window = windows; window != NULL; window = window->next) {
1162 /* Check if the mouse is within the window. */
1163 if(mxc >= window->x &&
1164 mxc <= window->x + window->w &&
1165 myc >= window->y &&
1166 myc <= window->y + window->h) {
1167 break;
1168 }
1169 }
1170 }
1171
1172
1173 /* If we didn't find any window, and there are no windows
1174 open, the mouse pointer will definately be within the
1175 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001176 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001177 window = &desktop_window;
1178 }
1179
adamdunkels965e2922003-06-30 20:44:57 +00001180 /* If the mouse pointer moves around outside of the
1181 currently focused window (or dialog), we should not have
1182 any focused widgets in the focused window so we make sure
1183 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001184 if(windows != NULL &&
1185 window != windows &&
1186 windows->focused != NULL){
1187 add_redrawwidget(windows->focused);
1188 windows->focused = NULL;
1189 redraw |= REDRAW_WIDGETS;
1190 }
1191
1192 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001193 /* If the mouse was clicked outside of the current window,
1194 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001195 if(dialog == NULL &&
1196 window != &desktop_window &&
1197 window != windows &&
1198 mouse_clicked) {
1199 /* Bring window to front. */
1200 ctk_window_open(window);
1201 redraw |= REDRAW_ALL;
1202 } else {
1203
adamdunkels965e2922003-06-30 20:44:57 +00001204 /* Find out which widget currently is under the mouse
1205 pointer and give it focus, unless it already has
1206 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001207 mxc = mxc - window->x - 1;
1208 myc = myc - window->y - 1;
1209
adamdunkels965e2922003-06-30 20:44:57 +00001210 /* See if the mouse pointer is on a widget. If so, it
1211 should be selected and, if the button is clicked,
1212 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001213 for(widget = window->active; widget != NULL;
1214 widget = widget->next) {
1215 if(mxc >= widget->x &&
1216 mxc <= widget->x + widget->w &&
1217 (myc == widget->y ||
1218 ((widget->type == CTK_WIDGET_BITMAP ||
1219 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1220 widget->type == CTK_WIDGET_ICON) &&
1221 (myc >= widget->y &&
1222 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1223 break;
1224 }
1225 }
1226
1227
adamdunkels58917a82003-04-18 00:18:38 +00001228 if(mouse_moved &&
1229 (window != &desktop_window ||
1230 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001231 dispatcher_emit(ctk_signal_pointer_move, NULL,
1232 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001233
adamdunkelsb2486562003-04-11 20:22:03 +00001234 if(window->focused != NULL &&
1235 widget != window->focused) {
1236 add_redrawwidget(window->focused);
1237 if(CTK_WIDGET_TYPE(window->focused) ==
1238 CTK_WIDGET_TEXTENTRY) {
1239 ((struct ctk_textentry *)(window->focused))->state =
1240 CTK_TEXTENTRY_NORMAL;
1241 }
1242 window->focused = NULL;
1243 }
1244 redraw |= REDRAW_WIDGETS;
1245 if(widget != NULL) {
1246 select_widget(widget);
1247 }
1248 }
1249
1250 if(mouse_button_changed) {
1251 dispatcher_emit(ctk_signal_pointer_button,
1252 (ek_data_t)mouse_button,
1253 window->owner);
1254 if(mouse_clicked && widget != NULL) {
1255 select_widget(widget);
1256 redraw |= activate(widget);
1257 }
1258 }
1259 }
1260 }
1261 }
adamdunkelsc4902862003-04-09 00:30:45 +00001262 }
1263 }
adamdunkels19a787c2003-04-09 09:22:24 +00001264#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001265
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001267
1268 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001269
1270 screensaver_timer = 0;
1271
adamdunkelsb2486562003-04-11 20:22:03 +00001272 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001273
1274 if(dialog != NULL) {
1275 window = dialog;
1276 } else if(windows != NULL) {
1277 window = windows;
1278 } else {
1279 window = &desktop_window;
1280 }
1281 widget = window->focused;
1282
1283
1284 if(widget != NULL &&
1285 widget->type == CTK_WIDGET_TEXTENTRY &&
1286 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1287 textentry_input(c, (struct ctk_textentry *)widget);
1288 add_redrawwidget(widget);
1289#if CTK_CONF_MENUS
1290 } else if(menus.open != NULL) {
1291 redraw |= menus_input(c);
1292#endif /* CTK_CONF_MENUS */
1293 } else {
1294 switch(c) {
1295 case CH_CURS_RIGHT:
1296 switch_focus_widget(RIGHT);
1297 break;
1298 case CH_CURS_DOWN:
1299 switch_focus_widget(DOWN);
1300 break;
1301 case CH_CURS_LEFT:
1302 switch_focus_widget(LEFT);
1303 break;
1304 case CH_CURS_UP:
1305 switch_focus_widget(UP);
1306 break;
1307 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001308 if(widget != NULL) {
1309 redraw |= activate(widget);
1310 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001311 break;
1312#if CTK_CONF_MENUS
1313 case CTK_CONF_MENU_KEY:
1314 if(dialog == NULL) {
1315 if(lastmenu == NULL) {
1316 menus.open = menus.menus;
1317 } else {
1318 menus.open = lastmenu;
1319 }
1320 menus.open->active = 0;
1321 redraw |= REDRAW_MENUS;
1322 }
1323 break;
1324#endif /* CTK_CONF_MENUS */
1325 case CTK_CONF_WINDOWSWITCH_KEY:
1326 if(windows != NULL) {
1327 for(window = windows; window->next != NULL;
1328 window = window->next);
1329 ctk_window_open(window);
adamdunkels965e2922003-06-30 20:44:57 +00001330 ctk_desktop_redraw(NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001331 }
1332 break;
1333 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001334 if(widget != NULL &&
1335 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001336 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1337 textentry_input(c, (struct ctk_textentry *)widget);
1338 add_redrawwidget(widget);
1339 } else {
1340 dispatcher_emit(ctk_signal_keypress, (void *)c,
1341 window->owner);
1342 }
1343 break;
1344 }
1345 }
1346
1347 if(redraw & REDRAW_WIDGETS) {
1348 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001349 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001350 }
1351 redraw &= ~REDRAW_WIDGETS;
1352 redraw_widgetptr = 0;
1353 }
1354 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001355#if CTK_CONF_WINDOWMOVE
1356 } else if(mode == CTK_MODE_WINDOWMOVE) {
1357
1358 redraw = 0;
1359
1360 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001361
1362#if CTK_CONF_MOUSE_SUPPORT
1363
1364 /* If the mouse has moved, we move the window as well. */
1365 if(mouse_moved) {
1366
1367 if(window->w + mxc + 2 >= width) {
1368 window->x = width - 2 - window->w;
1369 } else {
1370 window->x = mxc;
1371 }
1372
1373 if(window->h + myc + 2 >= height) {
1374 window->y = height - 2 - window->h;
1375 } else {
1376 window->y = myc;
1377 }
1378 if(window->y > 0) {
1379 --window->y;
1380 }
1381
1382 redraw = REDRAW_ALL;
1383 }
1384
1385 /* Check if the mouse has been clicked, and stop moving the window
1386 if so. */
1387 if(mouse_button_changed &&
1388 mouse_button == 0) {
1389 mode = CTK_MODE_NORMAL;
1390 redraw = REDRAW_ALL;
1391 }
1392#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001393
1394 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1395
1396 screensaver_timer = 0;
1397
1398 c = ctk_arch_getkey();
1399
1400 switch(c) {
1401 case CH_CURS_RIGHT:
1402 ++window->x;
1403 if(window->x + window->w + 1 >= width) {
1404 --window->x;
1405 }
1406 redraw = REDRAW_ALL;
1407 break;
1408 case CH_CURS_LEFT:
1409 if(window->x > 0) {
1410 --window->x;
1411 }
1412 redraw = REDRAW_ALL;
1413 break;
1414 case CH_CURS_DOWN:
1415 ++window->y;
1416 if(window->y + window->h + 2 >= height) {
1417 --window->y;
1418 }
1419 redraw = REDRAW_ALL;
1420 break;
1421 case CH_CURS_UP:
1422 if(window->y > 0) {
1423 --window->y;
1424 }
1425 redraw = REDRAW_ALL;
1426 break;
1427 case CH_ENTER:
1428 case CH_ESC:
1429 mode = CTK_MODE_NORMAL;
1430 redraw = REDRAW_ALL;
1431 break;
1432 }
1433 }
adamdunkelsb2486562003-04-11 20:22:03 +00001434 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001435 do_redraw_all(1, height);
1436 }
adamdunkelsb2486562003-04-11 20:22:03 +00001437 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001438#endif /* CTK_CONF_WINDOWMOVE */
1439 }
adamdunkelsb2486562003-04-11 20:22:03 +00001440
1441 if(redraw & REDRAW_ALL) {
1442 do_redraw_all(1, height);
1443#if CTK_CONF_MENUS
1444 } else if(redraw & REDRAW_MENUPART) {
1445 do_redraw_all(1, maxnitems + 1);
1446 } else if(redraw & REDRAW_MENUS) {
1447 ctk_draw_menus(&menus);
1448#endif /* CTK_CONF_MENUS */
1449 } else if(redraw & REDRAW_FOCUS) {
1450 if(dialog != NULL) {
1451 ctk_window_redraw(dialog);
1452 } else if(windows != NULL) {
1453 ctk_window_redraw(windows);
1454 } else {
1455 ctk_window_redraw(&desktop_window);
1456 }
1457 } else if(redraw & REDRAW_WIDGETS) {
1458 for(i = 0; i < redraw_widgetptr; ++i) {
1459 ctk_widget_redraw(redraw_widgets[i]);
1460 }
1461 }
1462 redraw = 0;
1463 redraw_widgetptr = 0;
1464
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001465}
1466/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001467static
1468DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001469{
adamdunkels78c03dc2003-04-09 13:45:05 +00001470 DISPATCHER_SIGHANDLER_ARGS(s, data);
1471
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001472 if(s == ctk_signal_timer) {
1473 if(mode == CTK_MODE_NORMAL) {
1474 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001475 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001476#if CTK_CONF_SCREENSAVER
1477 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1478 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001479#ifdef CTK_SCREENSAVER_INIT
1480 CTK_SCREENSAVER_INIT();
1481#endif /* CTK_SCREENSAVER_INIT */
1482 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001483#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001484 screensaver_timer = 0;
1485 }
1486 }
1487 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1488 }
1489}
1490/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001491