blob: 65b336ee9d05f81e75a9e4d72319dde15d7dfb2c [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 *
adamdunkelscf90b0d2003-08-09 13:34:16 +000035 * $Id: ctk.c,v 1.23 2003/08/09 13:34:16 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
adamdunkels591724c2003-08-01 00:07:19 +000047#include <string.h>
48
adamdunkelsca9ddcb2003-03-19 14:13:31 +000049static unsigned char height, width;
50
51static unsigned char mode;
52
53static struct ctk_window desktop_window;
54static struct ctk_window *windows;
55static struct ctk_window *dialog;
56
57#if CTK_CONF_MENUS
58static struct ctk_menus menus;
59static struct ctk_menu *lastmenu;
60static struct ctk_menu desktopmenu;
61#endif /* CTK_CONF_MENUS */
62
63#ifndef NULL
64#define NULL (void *)0
65#endif /* NULL */
66
67
68#define REDRAW_NONE 0
69#define REDRAW_ALL 1
70#define REDRAW_FOCUS 2
71#define REDRAW_WIDGETS 4
72#define REDRAW_MENUS 8
73#define REDRAW_MENUPART 16
74
75#define MAX_REDRAWWIDGETS 4
76static unsigned char redraw;
77static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
78static unsigned char redraw_widgetptr;
79static unsigned char maxnitems;
80
81static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000082#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000083#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000084#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000085#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000086#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000087
adamdunkelsc4902862003-04-09 00:30:45 +000088static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000089static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +000090 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091static ek_id_t ctkid;
92
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093ek_signal_t ctk_signal_keypress,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094 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);
adamdunkelscf90b0d2003-08-09 13:34:16 +0000118static u16_t start, current;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000119/*#define SCREENSAVER_TIMEOUT (5*60)*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000120
121#if CTK_CONF_MENUS
122/*-----------------------------------------------------------------------------------*/
123/* make_desktopmenu(void)
124 *
125 * Creates the leftmost menu, "Desktop". Since the desktop menu
126 * contains the list of all open windows, this function will be called
127 * whenever a window is opened or closed.
128 */
129static void
130make_desktopmenu(void)
131{
132 struct ctk_window *w;
133
134 desktopmenu.nitems = 0;
135
136 if(windows == NULL) {
137 ctk_menuitem_add(&desktopmenu, "(No windows)");
138 } else {
139 for(w = windows; w != NULL; w = w->next) {
140 ctk_menuitem_add(&desktopmenu, w->title);
141 }
142 }
143}
144#endif /* CTK_CONF_MENUS */
145/*-----------------------------------------------------------------------------------*/
146/* ctk_init(void)
147 *
148 * Initializes CTK. Must be called before any other CTK function.
149 */
150void
151ctk_init(void)
152{
153 ctkid = dispatcher_start(&p);
154
155 windows = NULL;
156 dialog = NULL;
157
158#if CTK_CONF_MENUS
159 ctk_menu_new(&desktopmenu, "Desktop");
160 make_desktopmenu();
161 menus.menus = menus.desktopmenu = &desktopmenu;
162#endif /* CTK_CONF_MENUS */
163
adamdunkelsb2486562003-04-11 20:22:03 +0000164#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000165 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000166 ctk_mouse_show();
167#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000168
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000169 ctk_draw_init();
170
171 height = ctk_draw_height();
172 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000173
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000174 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000175
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000176 ctk_signal_keypress = 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
201 mode = CTK_MODE_NORMAL;
202
203 iconx = ICONX_START;
204 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000205
206 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000207
208 start = ek_clock();
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;
adamdunkels591724c2003-08-01 00:07:19 +0000246 redraw |= REDRAW_FOCUS;
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);
adamdunkels47efbc42003-08-07 00:03:26 +0000608 } else if(dialog == NULL &&
609 window == windows ||
adamdunkels66109622003-04-24 17:17:10 +0000610 window == &desktop_window) {
611 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000612 }
613 }
614 }
615}
616/*-----------------------------------------------------------------------------------*/
617void
adamdunkelsd07a5422003-04-05 12:22:35 +0000618ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
619 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000620{
621 if(widget->type == CTK_WIDGET_LABEL ||
622 widget->type == CTK_WIDGET_SEPARATOR) {
623 widget->next = window->inactive;
624 window->inactive = widget;
625 widget->window = window;
626 } else {
627 widget->next = window->active;
628 window->active = widget;
629 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000630 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000631 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000632 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000633 }
634}
635/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000636unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000637ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000638{
639 return ctk_draw_width();
640}
641/*-----------------------------------------------------------------------------------*/
642unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000643ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000644{
645 return ctk_draw_height();
646}
647/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000648static void
adamdunkelsb2486562003-04-11 20:22:03 +0000649select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000650{
651 struct ctk_window *window;
652
653 window = focus->window;
654
655 if(focus != window->focused) {
656 window->focused = focus;
657 /* The operation changed the focus, so we emit a "hover" signal
658 for those widgets that support it. */
659
660 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
661 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
662 window->owner);
663 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
664 dispatcher_emit(ctk_signal_button_hover, window->focused,
665 window->owner);
666 }
667
668 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000669
670 dispatcher_emit(ctk_signal_widget_select, focus,
671 focus->window->owner);
672
adamdunkelse0683312003-04-09 09:02:52 +0000673 }
674
675}
676/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000677#define UP 0
678#define DOWN 1
679#define LEFT 2
680#define RIGHT 3
681static void
682switch_focus_widget(unsigned char direction)
683{
684 register struct ctk_window *window;
685 register struct ctk_widget *focus;
686 struct ctk_widget *widget;
687
688
689 if(dialog != NULL) {
690 window = dialog;
691 } else {
692 window = windows;
693 }
694
695 /* If there are no windows open, we move focus around between the
696 icons on the root window instead. */
697 if(window == NULL) {
698 window = &desktop_window;
699 }
700
701 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000702 if(focus == NULL) {
703 focus = window->active;
704 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000705 add_redrawwidget(focus);
706
707 if((direction & 1) == 0) {
708 /* Move focus "up" */
709 focus = focus->next;
710 } else {
711 /* Move focus "down" */
712 for(widget = window->active;
713 widget != NULL; widget = widget->next) {
714 if(widget->next == focus) {
715 break;
716 }
717 }
718 focus = widget;
719 if(focus == NULL) {
720 if(window->active != NULL) {
721 for(focus = window->active;
722 focus->next != NULL; focus = focus->next);
723 }
724 }
725 }
726 if(focus == NULL) {
727 focus = window->active;
728 }
adamdunkelse0683312003-04-09 09:02:52 +0000729
adamdunkelsb2486562003-04-11 20:22:03 +0000730 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000731}
732/*-----------------------------------------------------------------------------------*/
733#if CTK_CONF_MENUS
734static void
735switch_open_menu(unsigned char rightleft)
736{
737 struct ctk_menu *menu;
738
739 if(rightleft == 0) {
740 /* Move right */
741 for(menu = menus.menus; menu != NULL; menu = menu->next) {
742 if(menu->next == menus.open) {
743 break;
744 }
745 }
746 lastmenu = menus.open;
747 menus.open = menu;
748 if(menus.open == NULL) {
749 for(menu = menus.menus;
750 menu->next != NULL; menu = menu->next);
751 menus.open = menu;
752 }
753 } else {
754 /* Move to left */
755 lastmenu = menus.open;
756 menus.open = menus.open->next;
757 if(menus.open == NULL) {
758 menus.open = menus.menus;
759 }
760 }
761
adamdunkels66109622003-04-24 17:17:10 +0000762 menus.open->active = 0;
763
764 /* if(menus.open->nitems > maxnitems) {
765 maxnitems = menus.open->nitems;
766 }*/
767
adamdunkels965e2922003-06-30 20:44:57 +0000768 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000769}
770/*-----------------------------------------------------------------------------------*/
771static void
772switch_menu_item(unsigned char updown)
773{
774 register struct ctk_menu *m;
775
776 m = menus.open;
777
778 if(updown == 0) {
779 /* Move up */
780 if(m->active == 0) {
781 m->active = m->nitems - 1;
782 } else {
783 --m->active;
784 if(m->items[m->active].title[0] == '-') {
785 --m->active;
786 }
787 }
788 } else {
789 /* Move down */
790 if(m->active >= m->nitems - 1) {
791 m->active = 0;
792 } else {
793 ++m->active;
794 if(m->items[m->active].title[0] == '-') {
795 ++m->active;
796 }
797 }
798 }
799
800}
801#endif /* CTK_CONF_MENUS */
802/*-----------------------------------------------------------------------------------*/
803static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000804activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805{
806 static unsigned char len;
807
808 if(w->type == CTK_WIDGET_BUTTON) {
809 if(w == (struct ctk_widget *)&windows->closebutton) {
810#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000811 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000812 ctk_window_close(windows);
813 return REDRAW_ALL;
814#endif /* CTK_CONF_WINDOWCLOSE */
815 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
816#if CTK_CONF_WINDOWCLOSE
817 mode = CTK_MODE_WINDOWMOVE;
818#endif /* CTK_CONF_WINDOWCLOSE */
819 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000820 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000821 w->window->owner);
822 }
823#if CTK_CONF_ICONS
824 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000825 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826 w->widget.icon.owner);
827#endif /* CTK_CONF_ICONS */
828 } else if(w->type == CTK_WIDGET_HYPERLINK) {
829 dispatcher_emit(ctk_signal_hyperlink_activate, w,
830 DISPATCHER_BROADCAST);
831 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
832 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
833 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
834 len = strlen(w->widget.textentry.text);
835 if(w->widget.textentry.xpos > len) {
836 w->widget.textentry.xpos = len;
837 }
838 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
839 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
840 }
841 add_redrawwidget(w);
842 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000843 } else {
844 dispatcher_emit(ctk_signal_widget_activate, w,
845 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000846 }
847 return REDRAW_NONE;
848}
849/*-----------------------------------------------------------------------------------*/
850static void
851textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000852 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000853{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000854 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000855 static unsigned char len, txpos, typos, tlen;
856
857 txpos = t->xpos;
858 typos = t->ypos;
859 tlen = t->len;
860
861 cptr = &t->text[txpos + typos * tlen];
862
863 switch(c) {
864 case CH_CURS_LEFT:
865 if(txpos > 0) {
866 --txpos;
867 }
868 break;
869
870 case CH_CURS_RIGHT:
871 if(txpos < tlen &&
872 *cptr != 0) {
873 ++txpos;
874 }
875 break;
876
877 case CH_CURS_UP:
878#if CTK_CONF_TEXTENTRY_MULTILINE
879 if(t->h == 1) {
880 txpos = 0;
881 } else {
882 if(typos > 0) {
883 --typos;
884 } else {
885 t->state = CTK_TEXTENTRY_NORMAL;
886 }
887 }
888#else
889 txpos = 0;
890#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
891 break;
892
893 case CH_CURS_DOWN:
894#if CTK_CONF_TEXTENTRY_MULTILINE
895 if(t->h == 1) {
896 txpos = strlen(t->text);
897 } else {
898 if(typos < t->h - 1) {
899 ++typos;
900 } else {
901 t->state = CTK_TEXTENTRY_NORMAL;
902 }
903 }
904#else
905 txpos = strlen(t->text);
906#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
907 break;
908
909 case CH_ENTER:
910#if CTK_CONF_TEXTENTRY_MULTILINE
911 if(t->h == 1) {
912 t->state = CTK_TEXTENTRY_NORMAL;
913 } else {
914 if(typos < t->h - 1) {
915 ++typos;
916 txpos = 0;
917 } else {
918 t->state = CTK_TEXTENTRY_NORMAL;
919 }
920 }
921#else
922 t->state = CTK_TEXTENTRY_NORMAL;
923#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
924 break;
925
926 default:
927 len = tlen - txpos - 1;
928 if(c == CH_DEL) {
929 if(txpos > 0 && len > 0) {
930 strncpy(cptr - 1, cptr,
931 len);
932 *(cptr + len - 1) = 0;
933 --txpos;
934 }
935 } else {
936 if(len > 0) {
937 cptr2 = cptr + len - 1;
938 while(cptr2 + 1 > cptr) {
939 *(cptr2 + 1) = *cptr2;
940 --cptr2;
941 }
942
943 *cptr = c;
944 ++txpos;
945 }
946 }
947 break;
948 }
949
950 t->xpos = txpos;
951 t->ypos = typos;
952}
953/*-----------------------------------------------------------------------------------*/
954#if CTK_CONF_MENUS
955static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000956activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000957{
958 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000959
960 lastmenu = menus.open;
961 if(menus.open == &desktopmenu) {
962 for(w = windows; w != NULL; w = w->next) {
963 if(w->title == desktopmenu.items[desktopmenu.active].title) {
964 ctk_window_open(w);
965 menus.open = NULL;
966 return REDRAW_ALL;
967 }
968 }
969 } else {
970 dispatcher_emit(ctk_signal_menu_activate, menus.open,
971 DISPATCHER_BROADCAST);
972 }
973 menus.open = NULL;
974 return REDRAW_MENUPART;
975}
976/*-----------------------------------------------------------------------------------*/
977static unsigned char
978menus_input(ctk_arch_key_t c)
979{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000980
981 if(menus.open->nitems > maxnitems) {
982 maxnitems = menus.open->nitems;
983 }
984
985
986 switch(c) {
987 case CH_CURS_RIGHT:
988 switch_open_menu(1);
989
990 return REDRAW_MENUPART;
991
992 case CH_CURS_DOWN:
993 switch_menu_item(1);
994 return REDRAW_MENUS;
995
996 case CH_CURS_LEFT:
997 switch_open_menu(0);
998 return REDRAW_MENUPART;
999
1000 case CH_CURS_UP:
1001 switch_menu_item(0);
1002 return REDRAW_MENUS;
1003
1004 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001005 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001006
adamdunkels88ed9c42003-03-28 12:10:09 +00001007 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001008 lastmenu = menus.open;
1009 menus.open = NULL;
1010 return REDRAW_MENUPART;
1011 }
adamdunkelsb2486562003-04-11 20:22:03 +00001012
1013 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001014}
1015#endif /* CTK_CONF_MENUS */
1016/*-----------------------------------------------------------------------------------*/
1017static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001018timer(void)
1019{
1020 if(mode == CTK_MODE_NORMAL) {
1021 ++screensaver_timer;
1022 if(screensaver_timer == ctk_screensaver_timeout) {
1023#if CTK_CONF_SCREENSAVER
1024 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1025 DISPATCHER_BROADCAST);
1026#ifdef CTK_SCREENSAVER_INIT
1027 CTK_SCREENSAVER_INIT();
1028#endif /* CTK_SCREENSAVER_INIT */
1029 mode = CTK_MODE_SCREENSAVER;
1030#endif /* CTK_CONF_SCREENSAVER */
1031 screensaver_timer = 0;
1032 }
1033 }
1034}
1035/*-----------------------------------------------------------------------------------*/
1036static void
adamdunkelsc4902862003-04-09 00:30:45 +00001037ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001038{
1039 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001040 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001041 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001042 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001043 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001044#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001045 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1046 mouse_clicked;
1047 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001048 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001049
adamdunkels19a787c2003-04-09 09:22:24 +00001050#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001051
1052
1053 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001054
adamdunkelscf90b0d2003-08-09 13:34:16 +00001055 if((current - start) >= CLK_TCK/2) {
1056 timer();
1057 start = current;
1058 }
1059
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001060#if CTK_CONF_MENUS
1061 if(menus.open != NULL) {
1062 maxnitems = menus.open->nitems;
1063 } else {
1064 maxnitems = 0;
1065 }
1066#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001067
1068#if CTK_CONF_MOUSE_SUPPORT
1069 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1070
1071 /* See if there is any change in the buttons. */
1072 if(ctk_mouse_button() != mouse_button) {
1073 mouse_button = ctk_mouse_button();
1074 mouse_button_changed = 1;
1075 if(mouse_button == 0) {
1076 mouse_clicked = 1;
1077 }
1078 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001079
adamdunkelsb2486562003-04-11 20:22:03 +00001080 /* Check if the mouse pointer has moved. */
1081 if(ctk_mouse_x() != mouse_x ||
1082 ctk_mouse_y() != mouse_y) {
1083 mouse_x = ctk_mouse_x();
1084 mouse_y = ctk_mouse_y();
1085 mouse_moved = 1;
1086 }
1087
1088 mxc = ctk_mouse_xtoc(mouse_x);
1089 myc = ctk_mouse_ytoc(mouse_y);
1090#endif /* CTK_CONF_MOUSE_SUPPORT */
1091
1092
adamdunkels66109622003-04-24 17:17:10 +00001093#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001094 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001095 if(ctk_arch_keyavail()
1096#if CTK_CONF_MOUSE_SUPPORT
1097 || mouse_moved || mouse_button_changed
1098#endif /* CTK_CONF_MOUSE_SUPPORT */
1099 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001100 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1101 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001102 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001103 }
adamdunkels66109622003-04-24 17:17:10 +00001104 } else
1105#endif /* CTK_CONF_SCREENSAVER */
1106 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001107#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001108 /* If there is any change in the mouse conditions, find out in
1109 which window the mouse pointer currently is in order to send
1110 the correct signals, or bring a window to focus. */
1111 if(mouse_moved || mouse_button_changed) {
1112 ctk_mouse_show();
1113 screensaver_timer = 0;
1114
1115 if(myc == 0) {
1116 /* Here we should do whatever needs to be done when the mouse
1117 moves around and clicks in the menubar. */
1118 if(mouse_clicked) {
1119 /* Find out which menu that the mouse pointer is in. Start
1120 with the ->next menu after the desktop menu. We assume
1121 that the menus start one character from the left screen
1122 side and that the desktop menu is farthest to the
1123 right. */
1124 menux = 1;
1125 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1126 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1127 break;
adamdunkelse0683312003-04-09 09:02:52 +00001128 }
adamdunkelsb2486562003-04-11 20:22:03 +00001129 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001130 }
adamdunkelsb2486562003-04-11 20:22:03 +00001131
1132 /* Also check desktop menu. */
1133 if(mxc >= width - 7 &&
1134 mxc <= width - 1) {
1135 menu = &desktopmenu;
1136 }
1137
1138 menus.open = menu;
1139 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001140 }
adamdunkelse0683312003-04-09 09:02:52 +00001141 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001142 --myc;
1143
1144 if(menus.open != NULL) {
1145 /* Do whatever needs to be done when a menu is open. */
1146
adamdunkelscf90b0d2003-08-09 13:34:16 +00001147 /* First check if the mouse pointer is in the currently open
1148 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001149 if(menus.open == &desktopmenu) {
1150 menux = width - CTK_CONF_MENUWIDTH;
1151 } else {
1152 menux = 1;
1153 for(menu = menus.menus->next; menu != menus.open;
1154 menu = menu->next) {
1155 menux += menu->titlelen;
1156 }
1157 }
1158
adamdunkelscf90b0d2003-08-09 13:34:16 +00001159 /* Find out which of the menu items the mouse is pointing
1160 to. */
adamdunkelsb2486562003-04-11 20:22:03 +00001161 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001162 if(myc <= menus.open->nitems) {
1163 menus.open->active = myc;
1164 } else {
1165 menus.open->active = menus.open->nitems - 1;
1166 }
adamdunkelsb2486562003-04-11 20:22:03 +00001167 }
1168
1169 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001170 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1171 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001172 redraw |= activate_menu();
1173 } else {
1174 lastmenu = menus.open;
1175 menus.open = NULL;
1176 redraw |= REDRAW_MENUPART;
1177 }
1178 } else {
1179 redraw |= REDRAW_MENUS;
1180 }
1181 } else {
1182
adamdunkels965e2922003-06-30 20:44:57 +00001183 /* Walk through the windows from top to bottom to see in
1184 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001185 if(dialog != NULL) {
1186 window = dialog;
1187 } else {
1188 for(window = windows; window != NULL; window = window->next) {
1189 /* Check if the mouse is within the window. */
1190 if(mxc >= window->x &&
1191 mxc <= window->x + window->w &&
1192 myc >= window->y &&
1193 myc <= window->y + window->h) {
1194 break;
1195 }
1196 }
1197 }
1198
1199
1200 /* If we didn't find any window, and there are no windows
1201 open, the mouse pointer will definately be within the
1202 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001203 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001204 window = &desktop_window;
1205 }
1206
adamdunkels965e2922003-06-30 20:44:57 +00001207 /* If the mouse pointer moves around outside of the
1208 currently focused window (or dialog), we should not have
1209 any focused widgets in the focused window so we make sure
1210 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001211 if(windows != NULL &&
1212 window != windows &&
1213 windows->focused != NULL){
1214 add_redrawwidget(windows->focused);
1215 windows->focused = NULL;
1216 redraw |= REDRAW_WIDGETS;
1217 }
1218
1219 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001220 /* If the mouse was clicked outside of the current window,
1221 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001222 if(dialog == NULL &&
1223 window != &desktop_window &&
1224 window != windows &&
1225 mouse_clicked) {
1226 /* Bring window to front. */
1227 ctk_window_open(window);
1228 redraw |= REDRAW_ALL;
1229 } else {
1230
adamdunkels965e2922003-06-30 20:44:57 +00001231 /* Find out which widget currently is under the mouse
1232 pointer and give it focus, unless it already has
1233 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001234 mxc = mxc - window->x - 1;
1235 myc = myc - window->y - 1;
1236
adamdunkels965e2922003-06-30 20:44:57 +00001237 /* See if the mouse pointer is on a widget. If so, it
1238 should be selected and, if the button is clicked,
1239 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001240 for(widget = window->active; widget != NULL;
1241 widget = widget->next) {
1242 if(mxc >= widget->x &&
1243 mxc <= widget->x + widget->w &&
1244 (myc == widget->y ||
1245 ((widget->type == CTK_WIDGET_BITMAP ||
1246 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1247 widget->type == CTK_WIDGET_ICON) &&
1248 (myc >= widget->y &&
1249 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1250 break;
1251 }
1252 }
1253
1254
adamdunkels58917a82003-04-18 00:18:38 +00001255 if(mouse_moved &&
1256 (window != &desktop_window ||
1257 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001258 dispatcher_emit(ctk_signal_pointer_move, NULL,
1259 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001260
adamdunkelsb2486562003-04-11 20:22:03 +00001261 if(window->focused != NULL &&
1262 widget != window->focused) {
1263 add_redrawwidget(window->focused);
1264 if(CTK_WIDGET_TYPE(window->focused) ==
1265 CTK_WIDGET_TEXTENTRY) {
1266 ((struct ctk_textentry *)(window->focused))->state =
1267 CTK_TEXTENTRY_NORMAL;
1268 }
1269 window->focused = NULL;
1270 }
1271 redraw |= REDRAW_WIDGETS;
1272 if(widget != NULL) {
1273 select_widget(widget);
1274 }
1275 }
1276
1277 if(mouse_button_changed) {
1278 dispatcher_emit(ctk_signal_pointer_button,
1279 (ek_data_t)mouse_button,
1280 window->owner);
1281 if(mouse_clicked && widget != NULL) {
1282 select_widget(widget);
1283 redraw |= activate(widget);
1284 }
1285 }
1286 }
1287 }
1288 }
adamdunkelsc4902862003-04-09 00:30:45 +00001289 }
1290 }
adamdunkels19a787c2003-04-09 09:22:24 +00001291#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001292
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001293 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001294
1295 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001296
1297 screensaver_timer = 0;
1298
adamdunkelsb2486562003-04-11 20:22:03 +00001299 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001300
1301 if(dialog != NULL) {
1302 window = dialog;
1303 } else if(windows != NULL) {
1304 window = windows;
1305 } else {
1306 window = &desktop_window;
1307 }
1308 widget = window->focused;
1309
1310
1311 if(widget != NULL &&
1312 widget->type == CTK_WIDGET_TEXTENTRY &&
1313 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1314 textentry_input(c, (struct ctk_textentry *)widget);
1315 add_redrawwidget(widget);
1316#if CTK_CONF_MENUS
1317 } else if(menus.open != NULL) {
1318 redraw |= menus_input(c);
1319#endif /* CTK_CONF_MENUS */
1320 } else {
1321 switch(c) {
1322 case CH_CURS_RIGHT:
1323 switch_focus_widget(RIGHT);
1324 break;
1325 case CH_CURS_DOWN:
1326 switch_focus_widget(DOWN);
1327 break;
1328 case CH_CURS_LEFT:
1329 switch_focus_widget(LEFT);
1330 break;
1331 case CH_CURS_UP:
1332 switch_focus_widget(UP);
1333 break;
1334 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001335 if(widget != NULL) {
1336 redraw |= activate(widget);
1337 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001338 break;
1339#if CTK_CONF_MENUS
1340 case CTK_CONF_MENU_KEY:
1341 if(dialog == NULL) {
1342 if(lastmenu == NULL) {
1343 menus.open = menus.menus;
1344 } else {
1345 menus.open = lastmenu;
1346 }
1347 menus.open->active = 0;
1348 redraw |= REDRAW_MENUS;
1349 }
1350 break;
1351#endif /* CTK_CONF_MENUS */
1352 case CTK_CONF_WINDOWSWITCH_KEY:
1353 if(windows != NULL) {
1354 for(window = windows; window->next != NULL;
1355 window = window->next);
1356 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001357 }
1358 break;
1359 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001360 if(widget != NULL &&
1361 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001362 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1363 textentry_input(c, (struct ctk_textentry *)widget);
1364 add_redrawwidget(widget);
1365 } else {
1366 dispatcher_emit(ctk_signal_keypress, (void *)c,
1367 window->owner);
1368 }
1369 break;
1370 }
1371 }
1372
1373 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001374 widgetptr = redraw_widgets;
1375 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1376 /* if(redraw_widgets[i] != NULL) {
1377 ctk_widget_redraw(redraw_widgets[i]);
1378 }
1379 redraw_widgets[i] = NULL;*/
1380 ctk_widget_redraw(*widgetptr);
1381 *widgetptr = NULL;
1382 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001383 }
1384 redraw &= ~REDRAW_WIDGETS;
1385 redraw_widgetptr = 0;
1386 }
1387 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001388#if CTK_CONF_WINDOWMOVE
1389 } else if(mode == CTK_MODE_WINDOWMOVE) {
1390
1391 redraw = 0;
1392
1393 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001394
1395#if CTK_CONF_MOUSE_SUPPORT
1396
1397 /* If the mouse has moved, we move the window as well. */
1398 if(mouse_moved) {
1399
1400 if(window->w + mxc + 2 >= width) {
1401 window->x = width - 2 - window->w;
1402 } else {
1403 window->x = mxc;
1404 }
1405
1406 if(window->h + myc + 2 >= height) {
1407 window->y = height - 2 - window->h;
1408 } else {
1409 window->y = myc;
1410 }
1411 if(window->y > 0) {
1412 --window->y;
1413 }
1414
1415 redraw = REDRAW_ALL;
1416 }
1417
1418 /* Check if the mouse has been clicked, and stop moving the window
1419 if so. */
1420 if(mouse_button_changed &&
1421 mouse_button == 0) {
1422 mode = CTK_MODE_NORMAL;
1423 redraw = REDRAW_ALL;
1424 }
1425#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001426
1427 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1428
1429 screensaver_timer = 0;
1430
1431 c = ctk_arch_getkey();
1432
1433 switch(c) {
1434 case CH_CURS_RIGHT:
1435 ++window->x;
1436 if(window->x + window->w + 1 >= width) {
1437 --window->x;
1438 }
1439 redraw = REDRAW_ALL;
1440 break;
1441 case CH_CURS_LEFT:
1442 if(window->x > 0) {
1443 --window->x;
1444 }
1445 redraw = REDRAW_ALL;
1446 break;
1447 case CH_CURS_DOWN:
1448 ++window->y;
1449 if(window->y + window->h + 2 >= height) {
1450 --window->y;
1451 }
1452 redraw = REDRAW_ALL;
1453 break;
1454 case CH_CURS_UP:
1455 if(window->y > 0) {
1456 --window->y;
1457 }
1458 redraw = REDRAW_ALL;
1459 break;
1460 case CH_ENTER:
1461 case CH_ESC:
1462 mode = CTK_MODE_NORMAL;
1463 redraw = REDRAW_ALL;
1464 break;
1465 }
1466 }
adamdunkelsb2486562003-04-11 20:22:03 +00001467 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001468 do_redraw_all(1, height);
1469 }
adamdunkelsb2486562003-04-11 20:22:03 +00001470 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001471#endif /* CTK_CONF_WINDOWMOVE */
1472 }
adamdunkelsb2486562003-04-11 20:22:03 +00001473
1474 if(redraw & REDRAW_ALL) {
1475 do_redraw_all(1, height);
1476#if CTK_CONF_MENUS
1477 } else if(redraw & REDRAW_MENUPART) {
1478 do_redraw_all(1, maxnitems + 1);
1479 } else if(redraw & REDRAW_MENUS) {
1480 ctk_draw_menus(&menus);
1481#endif /* CTK_CONF_MENUS */
1482 } else if(redraw & REDRAW_FOCUS) {
1483 if(dialog != NULL) {
1484 ctk_window_redraw(dialog);
1485 } else if(windows != NULL) {
1486 ctk_window_redraw(windows);
1487 } else {
1488 ctk_window_redraw(&desktop_window);
1489 }
1490 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001491 widgetptr = redraw_widgets;
1492 /* for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkelsb2486562003-04-11 20:22:03 +00001493 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001494 }*/
1495 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1496 ctk_widget_redraw(*widgetptr);
1497 *widgetptr = NULL;
1498 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001499 }
1500 }
1501 redraw = 0;
1502 redraw_widgetptr = 0;
1503
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001504}
1505/*-----------------------------------------------------------------------------------*/
adamdunkelscf90b0d2003-08-09 13:34:16 +00001506#if 0
adamdunkels78c03dc2003-04-09 13:45:05 +00001507static
1508DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001509{
adamdunkels78c03dc2003-04-09 13:45:05 +00001510 DISPATCHER_SIGHANDLER_ARGS(s, data);
1511
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001512 if(s == ctk_signal_timer) {
1513 if(mode == CTK_MODE_NORMAL) {
1514 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001515 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001516#if CTK_CONF_SCREENSAVER
1517 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1518 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001519#ifdef CTK_SCREENSAVER_INIT
1520 CTK_SCREENSAVER_INIT();
1521#endif /* CTK_SCREENSAVER_INIT */
1522 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001523#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001524 screensaver_timer = 0;
1525 }
1526 }
1527 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1528 }
1529}
adamdunkelscf90b0d2003-08-09 13:34:16 +00001530#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001531/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001532