blob: dcc81b4663321b4777d454c85bbcddc242bbacd4 [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 *
adamdunkels591724c2003-08-01 00:07:19 +000035 * $Id: ctk.c,v 1.20 2003/08/01 00:07:19 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);
adamdunkels78c03dc2003-04-09 13:45:05 +000089static DISPATCHER_SIGHANDLER(ctk_sighandler, s, data);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000090static struct dispatcher_proc p =
adamdunkelsc4902862003-04-09 00:30:45 +000091 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, ctk_sighandler, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000092static ek_id_t ctkid;
93
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094ek_signal_t ctk_signal_keypress,
95 ctk_signal_timer,
96 ctk_signal_button_activate,
adamdunkels58917a82003-04-18 00:18:38 +000097 ctk_signal_widget_activate,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098 ctk_signal_button_hover,
adamdunkels58917a82003-04-18 00:18:38 +000099 ctk_signal_widget_select,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000100 ctk_signal_hyperlink_activate,
101 ctk_signal_hyperlink_hover,
102 ctk_signal_menu_activate,
adamdunkelsc4902862003-04-09 00:30:45 +0000103 ctk_signal_window_close,
104 ctk_signal_pointer_move,
adamdunkelsb2486562003-04-11 20:22:03 +0000105 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000106
adamdunkels66109622003-04-24 17:17:10 +0000107#if CTK_CONF_SCREENSAVER
108ek_signal_t ctk_signal_screensaver_start,
109 ctk_signal_screensaver_stop,
110 ctk_signal_screensaver_uninstall;
111#endif /* CTK_CONF_SCREENSAVER */
112
113
adamdunkels19a787c2003-04-09 09:22:24 +0000114#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000115unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000116#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000117
118static unsigned short screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000119unsigned short ctk_screensaver_timeout = (5*60);
120/*#define SCREENSAVER_TIMEOUT (5*60)*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000121
122#if CTK_CONF_MENUS
123/*-----------------------------------------------------------------------------------*/
124/* make_desktopmenu(void)
125 *
126 * Creates the leftmost menu, "Desktop". Since the desktop menu
127 * contains the list of all open windows, this function will be called
128 * whenever a window is opened or closed.
129 */
130static void
131make_desktopmenu(void)
132{
133 struct ctk_window *w;
134
135 desktopmenu.nitems = 0;
136
137 if(windows == NULL) {
138 ctk_menuitem_add(&desktopmenu, "(No windows)");
139 } else {
140 for(w = windows; w != NULL; w = w->next) {
141 ctk_menuitem_add(&desktopmenu, w->title);
142 }
143 }
144}
145#endif /* CTK_CONF_MENUS */
146/*-----------------------------------------------------------------------------------*/
147/* ctk_init(void)
148 *
149 * Initializes CTK. Must be called before any other CTK function.
150 */
151void
152ctk_init(void)
153{
154 ctkid = dispatcher_start(&p);
155
156 windows = NULL;
157 dialog = NULL;
158
159#if CTK_CONF_MENUS
160 ctk_menu_new(&desktopmenu, "Desktop");
161 make_desktopmenu();
162 menus.menus = menus.desktopmenu = &desktopmenu;
163#endif /* CTK_CONF_MENUS */
164
adamdunkelsb2486562003-04-11 20:22:03 +0000165#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000166 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000167 ctk_mouse_show();
168#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000169
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000170 ctk_draw_init();
171
172 height = ctk_draw_height();
173 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000174
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000175 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000176
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000177 ctk_signal_keypress = dispatcher_sigalloc();
178 ctk_signal_timer = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000179
180 ctk_signal_button_activate =
181 ctk_signal_widget_activate = dispatcher_sigalloc();
182
183 ctk_signal_button_hover =
184 ctk_signal_hyperlink_hover =
185 ctk_signal_widget_select = dispatcher_sigalloc();
186
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000187 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000188
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000189 ctk_signal_menu_activate = dispatcher_sigalloc();
190 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000191
192 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000193 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000194
195
196#if CTK_CONF_SCREENSAVER
197 ctk_signal_screensaver_start = dispatcher_sigalloc();
198 ctk_signal_screensaver_stop = dispatcher_sigalloc();
199 ctk_signal_screensaver_uninstall = dispatcher_sigalloc();
200#endif /* CTK_CONF_SCREENSAVER */
201
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000202 dispatcher_listen(ctk_signal_timer);
203 dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
204
205 mode = CTK_MODE_NORMAL;
206
207 iconx = ICONX_START;
208 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000209
210 redraw = REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000211}
212/*-----------------------------------------------------------------------------------*/
213/* void ctk_mode_set()
214 */
215void
216ctk_mode_set(unsigned char m) {
217 mode = m;
218}
219/*-----------------------------------------------------------------------------------*/
220unsigned char
221ctk_mode_get(void) {
222 return mode;
223}
224/*-----------------------------------------------------------------------------------*/
225void
adamdunkelsd07a5422003-04-05 12:22:35 +0000226ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227 ek_id_t id)
228{
229#if CTK_CONF_ICONS
230 icon->x = iconx;
231 icon->y = icony;
232 icon->widget.icon.owner = id;
233
234 icony += ICONY_DELTA;
235 if(icony >= ICONY_MAX) {
236 icony = ICONY_START;
237 iconx += ICONX_DELTA;
238 }
239
240 ctk_widget_add(&desktop_window, icon);
241#endif /* CTK_CONF_ICONS */
242}
243/*-----------------------------------------------------------------------------------*/
244void
245ctk_dialog_open(struct ctk_window *d)
246{
247 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000248 redraw |= REDRAW_FOCUS;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000249}
250/*-----------------------------------------------------------------------------------*/
251void
252ctk_dialog_close(void)
253{
254 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000255 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000256}
257/*-----------------------------------------------------------------------------------*/
258void
adamdunkelsd07a5422003-04-05 12:22:35 +0000259ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000260{
261 struct ctk_window *w2;
262
263 /* Check if already open. */
264 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
265 if(w2 == NULL) {
266 /* Not open, so we add it at the head of the list of open
267 windows. */
268 w->next = windows;
269 if(windows != NULL) {
270 windows->prev = w;
271 }
272 windows = w;
273 w->prev = NULL;
274 } else {
275 /* Window already open, so we move it to the front of the windows
276 list. */
277 if(w != windows) {
278 if(w->next != NULL) {
279 w->next->prev = w->prev;
280 }
281 if(w->prev != NULL) {
282 w->prev->next = w->next;
283 }
284 w->next = windows;
285 windows->prev = w;
286 windows = w;
287 w->prev = NULL;
288 }
289 }
290
291#if CTK_CONF_MENUS
292 /* Recreate the Desktop menu's window entries.*/
293 make_desktopmenu();
294#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000295
296 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000297}
298/*-----------------------------------------------------------------------------------*/
299void
300ctk_window_close(struct ctk_window *w)
301{
302 struct ctk_window *w2;
303
304 if(w == NULL) {
305 return;
306 }
307
308 /* Check if the window to be closed is the first window on the
309 list. */
310 if(w == windows) {
311 windows = w->next;
312 if(windows != NULL) {
313 windows->prev = NULL;
314 }
315 w->next = w->prev = NULL;
316 } else {
317 /* Otherwise we step through the list until we find the window
318 before the one to be closed. We then redirect its ->next
319 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000320 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
321
322 if(w2 == NULL) {
323 /* The window wasn't open, so there is nothing more for us to
324 do. */
325 return;
326 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000327
328 if(w->next != NULL) {
329 w->next->prev = w->prev;
330 }
331 w2->next = w->next;
332
333 w->next = w->prev = NULL;
334 }
335
336#if CTK_CONF_MENUS
337 /* Recreate the Desktop menu's window entries.*/
338 make_desktopmenu();
339#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000340 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000341}
342/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000343static void
344make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000345{
346#if CTK_CONF_WINDOWMOVE
347 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
348#else
349 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
350#endif /* CTK_CONF_WINDOWMOVE */
351 CTK_WIDGET_ADD(window, &window->titlebutton);
352
353
354#if CTK_CONF_WINDOWCLOSE
355 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
356#else
357 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
358#endif /* CTK_CONF_WINDOWCLOSE */
359 CTK_WIDGET_ADD(window, &window->closebutton);
360}
361/*-----------------------------------------------------------------------------------*/
362void
363ctk_window_clear(struct ctk_window *window)
364{
365 window->active = window->inactive = window->focused = NULL;
366
367 make_windowbuttons(window);
368}
369/*-----------------------------------------------------------------------------------*/
370void
371ctk_menu_add(struct ctk_menu *menu)
372{
373#if CTK_CONF_MENUS
374 struct ctk_menu *m;
375
376 if(lastmenu == NULL) {
377 lastmenu = menu;
378 }
379
380 for(m = menus.menus; m->next != NULL; m = m->next) {
381 if(m == menu) {
382 return;
383 }
384 }
385 m->next = menu;
386 menu->next = NULL;
387#endif /* CTK_CONF_MENUS */
388}
389/*-----------------------------------------------------------------------------------*/
390void
391ctk_menu_remove(struct ctk_menu *menu)
392{
393#if CTK_CONF_MENUS
394 struct ctk_menu *m;
395
396 for(m = menus.menus; m->next != NULL; m = m->next) {
397 if(m->next == menu) {
398 m->next = menu->next;
399 return;
400 }
401 }
402#endif /* CTK_CONF_MENUS */
403}
404/*-----------------------------------------------------------------------------------*/
405static void
406do_redraw_all(unsigned char clipy1, unsigned char clipy2)
407{
408 struct ctk_window *w;
409 struct ctk_widget *widget;
410
411 if(mode != CTK_MODE_NORMAL &&
412 mode != CTK_MODE_WINDOWMOVE) {
413 return;
414 }
415
416 ctk_draw_clear(clipy1, clipy2);
417
418 /* Draw widgets in root window */
419 for(widget = desktop_window.active;
420 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000421 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000422 }
423
424 /* Draw windows */
425 if(windows != NULL) {
426 /* Find the last window.*/
427 for(w = windows; w->next != NULL; w = w->next);
428
429 /* Draw the windows from back to front. */
430 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000431 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000432 ctk_draw_window(w, 0, clipy1, clipy2);
433 }
434 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000435 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000436 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
437 }
438
439 /* Draw dialog (if any) */
440 if(dialog != NULL) {
441 ctk_draw_dialog(dialog);
442 }
443
444#if CTK_CONF_MENUS
445 ctk_draw_menus(&menus);
446#endif /* CTK_CONF_MENUS */
447}
448/*-----------------------------------------------------------------------------------*/
449void
adamdunkels965e2922003-06-30 20:44:57 +0000450ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000451{
452 if(DISPATCHER_CURRENT() == ctkid) {
453 if(mode == CTK_MODE_NORMAL ||
454 mode == CTK_MODE_WINDOWMOVE) {
455 do_redraw_all(1, height);
456 }
457 } else {
458 redraw |= REDRAW_ALL;
459 }
460}
461/*-----------------------------------------------------------------------------------*/
462void
463ctk_window_redraw(struct ctk_window *w)
464{
465 /* Only redraw the window if it is a dialog or if it is the foremost
466 window. */
467 if(mode != CTK_MODE_NORMAL) {
468 return;
469 }
470
471 if(w == dialog) {
472 ctk_draw_dialog(w);
473 } else if(dialog == NULL &&
474#if CTK_CONF_MENUS
475 menus.open == NULL &&
476#endif /* CTK_CONF_MENUS */
477 windows == w) {
478 ctk_draw_window(w, CTK_FOCUS_WINDOW,
479 0, height);
480 }
481}
482/*-----------------------------------------------------------------------------------*/
483static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000484window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000485 unsigned char w, unsigned char h,
486 char *title)
487{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000488
489 if(w >= width - 2) {
490 window->x = 0;
491 } else {
492 window->x = (width - w - 2) / 2;
493 }
494 if(h >= height - 3) {
495 window->y = 0;
496 } else {
497 window->y = (height - h - 1) / 2;
498 }
499
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000500 window->w = w;
501 window->h = h;
502 window->title = title;
503 if(title != NULL) {
504 window->titlelen = strlen(title);
505 } else {
506 window->titlelen = 0;
507 }
508 window->next = window->prev = NULL;
509 window->owner = DISPATCHER_CURRENT();
510 window->active = window->inactive = window->focused = NULL;
511}
512/*-----------------------------------------------------------------------------------*/
513void
514ctk_window_new(struct ctk_window *window,
515 unsigned char w, unsigned char h,
516 char *title)
517{
518 window_new(window, w, h, title);
519
520 make_windowbuttons(window);
521}
522/*-----------------------------------------------------------------------------------*/
523void
adamdunkelsd07a5422003-04-05 12:22:35 +0000524ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000525 unsigned char w, unsigned char h)
526{
527 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000528}
529/*-----------------------------------------------------------------------------------*/
530void
adamdunkelsd07a5422003-04-05 12:22:35 +0000531ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000532 char *title)
533{
534#if CTK_CONF_MENUS
535 menu->next = NULL;
536 menu->title = title;
537 menu->titlelen = strlen(title);
538 menu->active = 0;
539 menu->nitems = 0;
540#endif /* CTK_CONF_MENUS */
541}
542/*-----------------------------------------------------------------------------------*/
543unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000544ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000545 char *name)
546{
547#if CTK_CONF_MENUS
548 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
549 return 0;
550 }
551 menu->items[menu->nitems].title = name;
552 menu->items[menu->nitems].titlelen = strlen(name);
553 return menu->nitems++;
554#else
555 return 0;
556#endif /* CTK_CONF_MENUS */
557}
558/*-----------------------------------------------------------------------------------*/
559static void
560add_redrawwidget(struct ctk_widget *w)
561{
562 static unsigned char i;
563
564 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
565 redraw |= REDRAW_FOCUS;
566 } else {
567 redraw |= REDRAW_WIDGETS;
568 /* Check if it is in the queue already. If so, we don't add it
569 again. */
570 for(i = 0; i < redraw_widgetptr; ++i) {
571 if(redraw_widgets[i] == w) {
572 return;
573 }
574 }
575 redraw_widgets[redraw_widgetptr++] = w;
576 }
577}
578/*-----------------------------------------------------------------------------------*/
579void
580ctk_widget_redraw(struct ctk_widget *widget)
581{
582 struct ctk_window *window;
583
adamdunkels9f667f22003-04-16 18:29:19 +0000584 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000585 return;
586 }
587
588 /* If this function isn't called by CTK itself, we only queue the
589 redraw request. */
590 if(DISPATCHER_CURRENT() != ctkid) {
591 redraw |= REDRAW_WIDGETS;
592 add_redrawwidget(widget);
593 } else {
594
595 /* Only redraw widgets that are in the foremost window. If we
596 would allow redrawing widgets in non-focused windows, we would
597 have to redraw all the windows that cover the non-focused
598 window as well, which would lead to flickering.
599
600 Also, we avoid drawing any widgets when the menus are active.
601 */
602
603#if CTK_CONF_MENUS
604 if(menus.open == NULL)
605#endif /* CTK_CONF_MENUS */
606 {
607 window = widget->window;
608 if(window == dialog) {
609 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels66109622003-04-24 17:17:10 +0000610 } else if(window == windows ||
611 window == &desktop_window) {
612 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000613 }
614 }
615 }
616}
617/*-----------------------------------------------------------------------------------*/
618void
adamdunkelsd07a5422003-04-05 12:22:35 +0000619ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
620 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000621{
622 if(widget->type == CTK_WIDGET_LABEL ||
623 widget->type == CTK_WIDGET_SEPARATOR) {
624 widget->next = window->inactive;
625 window->inactive = widget;
626 widget->window = window;
627 } else {
628 widget->next = window->active;
629 window->active = widget;
630 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000631 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000632 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000633 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000634 }
635}
636/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000637unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000638ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000639{
640 return ctk_draw_width();
641}
642/*-----------------------------------------------------------------------------------*/
643unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000644ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000645{
646 return ctk_draw_height();
647}
648/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000649static void
adamdunkelsb2486562003-04-11 20:22:03 +0000650select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000651{
652 struct ctk_window *window;
653
654 window = focus->window;
655
656 if(focus != window->focused) {
657 window->focused = focus;
658 /* The operation changed the focus, so we emit a "hover" signal
659 for those widgets that support it. */
660
661 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
662 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
663 window->owner);
664 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
665 dispatcher_emit(ctk_signal_button_hover, window->focused,
666 window->owner);
667 }
668
669 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000670
671 dispatcher_emit(ctk_signal_widget_select, focus,
672 focus->window->owner);
673
adamdunkelse0683312003-04-09 09:02:52 +0000674 }
675
676}
677/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000678#define UP 0
679#define DOWN 1
680#define LEFT 2
681#define RIGHT 3
682static void
683switch_focus_widget(unsigned char direction)
684{
685 register struct ctk_window *window;
686 register struct ctk_widget *focus;
687 struct ctk_widget *widget;
688
689
690 if(dialog != NULL) {
691 window = dialog;
692 } else {
693 window = windows;
694 }
695
696 /* If there are no windows open, we move focus around between the
697 icons on the root window instead. */
698 if(window == NULL) {
699 window = &desktop_window;
700 }
701
702 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000703 if(focus == NULL) {
704 focus = window->active;
705 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000706 add_redrawwidget(focus);
707
708 if((direction & 1) == 0) {
709 /* Move focus "up" */
710 focus = focus->next;
711 } else {
712 /* Move focus "down" */
713 for(widget = window->active;
714 widget != NULL; widget = widget->next) {
715 if(widget->next == focus) {
716 break;
717 }
718 }
719 focus = widget;
720 if(focus == NULL) {
721 if(window->active != NULL) {
722 for(focus = window->active;
723 focus->next != NULL; focus = focus->next);
724 }
725 }
726 }
727 if(focus == NULL) {
728 focus = window->active;
729 }
adamdunkelse0683312003-04-09 09:02:52 +0000730
adamdunkelsb2486562003-04-11 20:22:03 +0000731 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000732}
733/*-----------------------------------------------------------------------------------*/
734#if CTK_CONF_MENUS
735static void
736switch_open_menu(unsigned char rightleft)
737{
738 struct ctk_menu *menu;
739
740 if(rightleft == 0) {
741 /* Move right */
742 for(menu = menus.menus; menu != NULL; menu = menu->next) {
743 if(menu->next == menus.open) {
744 break;
745 }
746 }
747 lastmenu = menus.open;
748 menus.open = menu;
749 if(menus.open == NULL) {
750 for(menu = menus.menus;
751 menu->next != NULL; menu = menu->next);
752 menus.open = menu;
753 }
754 } else {
755 /* Move to left */
756 lastmenu = menus.open;
757 menus.open = menus.open->next;
758 if(menus.open == NULL) {
759 menus.open = menus.menus;
760 }
761 }
762
adamdunkels66109622003-04-24 17:17:10 +0000763 menus.open->active = 0;
764
765 /* if(menus.open->nitems > maxnitems) {
766 maxnitems = menus.open->nitems;
767 }*/
768
adamdunkels965e2922003-06-30 20:44:57 +0000769 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000770}
771/*-----------------------------------------------------------------------------------*/
772static void
773switch_menu_item(unsigned char updown)
774{
775 register struct ctk_menu *m;
776
777 m = menus.open;
778
779 if(updown == 0) {
780 /* Move up */
781 if(m->active == 0) {
782 m->active = m->nitems - 1;
783 } else {
784 --m->active;
785 if(m->items[m->active].title[0] == '-') {
786 --m->active;
787 }
788 }
789 } else {
790 /* Move down */
791 if(m->active >= m->nitems - 1) {
792 m->active = 0;
793 } else {
794 ++m->active;
795 if(m->items[m->active].title[0] == '-') {
796 ++m->active;
797 }
798 }
799 }
800
801}
802#endif /* CTK_CONF_MENUS */
803/*-----------------------------------------------------------------------------------*/
804static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000805activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000806{
807 static unsigned char len;
808
809 if(w->type == CTK_WIDGET_BUTTON) {
810 if(w == (struct ctk_widget *)&windows->closebutton) {
811#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000812 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000813 ctk_window_close(windows);
814 return REDRAW_ALL;
815#endif /* CTK_CONF_WINDOWCLOSE */
816 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
817#if CTK_CONF_WINDOWCLOSE
818 mode = CTK_MODE_WINDOWMOVE;
819#endif /* CTK_CONF_WINDOWCLOSE */
820 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000821 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000822 w->window->owner);
823 }
824#if CTK_CONF_ICONS
825 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000826 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000827 w->widget.icon.owner);
828#endif /* CTK_CONF_ICONS */
829 } else if(w->type == CTK_WIDGET_HYPERLINK) {
830 dispatcher_emit(ctk_signal_hyperlink_activate, w,
831 DISPATCHER_BROADCAST);
832 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
833 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
834 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
835 len = strlen(w->widget.textentry.text);
836 if(w->widget.textentry.xpos > len) {
837 w->widget.textentry.xpos = len;
838 }
839 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
840 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
841 }
842 add_redrawwidget(w);
843 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000844 } else {
845 dispatcher_emit(ctk_signal_widget_activate, w,
846 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000847 }
848 return REDRAW_NONE;
849}
850/*-----------------------------------------------------------------------------------*/
851static void
852textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000853 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854{
855 static char *cptr, *cptr2;
856 static unsigned char len, txpos, typos, tlen;
857
858 txpos = t->xpos;
859 typos = t->ypos;
860 tlen = t->len;
861
862 cptr = &t->text[txpos + typos * tlen];
863
864 switch(c) {
865 case CH_CURS_LEFT:
866 if(txpos > 0) {
867 --txpos;
868 }
869 break;
870
871 case CH_CURS_RIGHT:
872 if(txpos < tlen &&
873 *cptr != 0) {
874 ++txpos;
875 }
876 break;
877
878 case CH_CURS_UP:
879#if CTK_CONF_TEXTENTRY_MULTILINE
880 if(t->h == 1) {
881 txpos = 0;
882 } else {
883 if(typos > 0) {
884 --typos;
885 } else {
886 t->state = CTK_TEXTENTRY_NORMAL;
887 }
888 }
889#else
890 txpos = 0;
891#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
892 break;
893
894 case CH_CURS_DOWN:
895#if CTK_CONF_TEXTENTRY_MULTILINE
896 if(t->h == 1) {
897 txpos = strlen(t->text);
898 } else {
899 if(typos < t->h - 1) {
900 ++typos;
901 } else {
902 t->state = CTK_TEXTENTRY_NORMAL;
903 }
904 }
905#else
906 txpos = strlen(t->text);
907#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
908 break;
909
910 case CH_ENTER:
911#if CTK_CONF_TEXTENTRY_MULTILINE
912 if(t->h == 1) {
913 t->state = CTK_TEXTENTRY_NORMAL;
914 } else {
915 if(typos < t->h - 1) {
916 ++typos;
917 txpos = 0;
918 } else {
919 t->state = CTK_TEXTENTRY_NORMAL;
920 }
921 }
922#else
923 t->state = CTK_TEXTENTRY_NORMAL;
924#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
925 break;
926
927 default:
928 len = tlen - txpos - 1;
929 if(c == CH_DEL) {
930 if(txpos > 0 && len > 0) {
931 strncpy(cptr - 1, cptr,
932 len);
933 *(cptr + len - 1) = 0;
934 --txpos;
935 }
936 } else {
937 if(len > 0) {
938 cptr2 = cptr + len - 1;
939 while(cptr2 + 1 > cptr) {
940 *(cptr2 + 1) = *cptr2;
941 --cptr2;
942 }
943
944 *cptr = c;
945 ++txpos;
946 }
947 }
948 break;
949 }
950
951 t->xpos = txpos;
952 t->ypos = typos;
953}
954/*-----------------------------------------------------------------------------------*/
955#if CTK_CONF_MENUS
956static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000957activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958{
959 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000960
961 lastmenu = menus.open;
962 if(menus.open == &desktopmenu) {
963 for(w = windows; w != NULL; w = w->next) {
964 if(w->title == desktopmenu.items[desktopmenu.active].title) {
965 ctk_window_open(w);
966 menus.open = NULL;
967 return REDRAW_ALL;
968 }
969 }
970 } else {
971 dispatcher_emit(ctk_signal_menu_activate, menus.open,
972 DISPATCHER_BROADCAST);
973 }
974 menus.open = NULL;
975 return REDRAW_MENUPART;
976}
977/*-----------------------------------------------------------------------------------*/
978static unsigned char
979menus_input(ctk_arch_key_t c)
980{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000981
982 if(menus.open->nitems > maxnitems) {
983 maxnitems = menus.open->nitems;
984 }
985
986
987 switch(c) {
988 case CH_CURS_RIGHT:
989 switch_open_menu(1);
990
991 return REDRAW_MENUPART;
992
993 case CH_CURS_DOWN:
994 switch_menu_item(1);
995 return REDRAW_MENUS;
996
997 case CH_CURS_LEFT:
998 switch_open_menu(0);
999 return REDRAW_MENUPART;
1000
1001 case CH_CURS_UP:
1002 switch_menu_item(0);
1003 return REDRAW_MENUS;
1004
1005 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001006 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001007
adamdunkels88ed9c42003-03-28 12:10:09 +00001008 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009 lastmenu = menus.open;
1010 menus.open = NULL;
1011 return REDRAW_MENUPART;
1012 }
adamdunkelsb2486562003-04-11 20:22:03 +00001013
1014 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001015}
1016#endif /* CTK_CONF_MENUS */
1017/*-----------------------------------------------------------------------------------*/
1018static void
adamdunkelsc4902862003-04-09 00:30:45 +00001019ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001020{
1021 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001022 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001023 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001024 register struct ctk_widget *widget;
1025#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001026 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1027 mouse_clicked;
1028 static unsigned char menux;
1029 struct ctk_menu *menu;
1030
adamdunkels19a787c2003-04-09 09:22:24 +00001031#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001032
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001033#if CTK_CONF_MENUS
1034 if(menus.open != NULL) {
1035 maxnitems = menus.open->nitems;
1036 } else {
1037 maxnitems = 0;
1038 }
1039#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001040
1041#if CTK_CONF_MOUSE_SUPPORT
1042 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1043
1044 /* See if there is any change in the buttons. */
1045 if(ctk_mouse_button() != mouse_button) {
1046 mouse_button = ctk_mouse_button();
1047 mouse_button_changed = 1;
1048 if(mouse_button == 0) {
1049 mouse_clicked = 1;
1050 }
1051 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001052
adamdunkelsb2486562003-04-11 20:22:03 +00001053 /* Check if the mouse pointer has moved. */
1054 if(ctk_mouse_x() != mouse_x ||
1055 ctk_mouse_y() != mouse_y) {
1056 mouse_x = ctk_mouse_x();
1057 mouse_y = ctk_mouse_y();
1058 mouse_moved = 1;
1059 }
1060
1061 mxc = ctk_mouse_xtoc(mouse_x);
1062 myc = ctk_mouse_ytoc(mouse_y);
1063#endif /* CTK_CONF_MOUSE_SUPPORT */
1064
1065
adamdunkels66109622003-04-24 17:17:10 +00001066#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001067 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001068 if(ctk_arch_keyavail()
1069#if CTK_CONF_MOUSE_SUPPORT
1070 || mouse_moved || mouse_button_changed
1071#endif /* CTK_CONF_MOUSE_SUPPORT */
1072 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001073 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1074 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001075 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001076 }
adamdunkels66109622003-04-24 17:17:10 +00001077 } else
1078#endif /* CTK_CONF_SCREENSAVER */
1079 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001080#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001081 /* If there is any change in the mouse conditions, find out in
1082 which window the mouse pointer currently is in order to send
1083 the correct signals, or bring a window to focus. */
1084 if(mouse_moved || mouse_button_changed) {
1085 ctk_mouse_show();
1086 screensaver_timer = 0;
1087
1088 if(myc == 0) {
1089 /* Here we should do whatever needs to be done when the mouse
1090 moves around and clicks in the menubar. */
1091 if(mouse_clicked) {
1092 /* Find out which menu that the mouse pointer is in. Start
1093 with the ->next menu after the desktop menu. We assume
1094 that the menus start one character from the left screen
1095 side and that the desktop menu is farthest to the
1096 right. */
1097 menux = 1;
1098 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1099 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1100 break;
adamdunkelse0683312003-04-09 09:02:52 +00001101 }
adamdunkelsb2486562003-04-11 20:22:03 +00001102 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001103 }
adamdunkelsb2486562003-04-11 20:22:03 +00001104
1105 /* Also check desktop menu. */
1106 if(mxc >= width - 7 &&
1107 mxc <= width - 1) {
1108 menu = &desktopmenu;
1109 }
1110
1111 menus.open = menu;
1112 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001113 }
adamdunkelse0683312003-04-09 09:02:52 +00001114 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001115 --myc;
1116
1117 if(menus.open != NULL) {
1118 /* Do whatever needs to be done when a menu is open. */
1119
1120 if(menus.open == &desktopmenu) {
1121 menux = width - CTK_CONF_MENUWIDTH;
1122 } else {
1123 menux = 1;
1124 for(menu = menus.menus->next; menu != menus.open;
1125 menu = menu->next) {
1126 menux += menu->titlelen;
1127 }
1128 }
1129
1130 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001131 if(myc <= menus.open->nitems) {
1132 menus.open->active = myc;
1133 } else {
1134 menus.open->active = menus.open->nitems - 1;
1135 }
adamdunkelsb2486562003-04-11 20:22:03 +00001136 }
1137
1138 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001139 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1140 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001141 redraw |= activate_menu();
1142 } else {
1143 lastmenu = menus.open;
1144 menus.open = NULL;
1145 redraw |= REDRAW_MENUPART;
1146 }
1147 } else {
1148 redraw |= REDRAW_MENUS;
1149 }
1150 } else {
1151
adamdunkels965e2922003-06-30 20:44:57 +00001152 /* Walk through the windows from top to bottom to see in
1153 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001154 if(dialog != NULL) {
1155 window = dialog;
1156 } else {
1157 for(window = windows; window != NULL; window = window->next) {
1158 /* Check if the mouse is within the window. */
1159 if(mxc >= window->x &&
1160 mxc <= window->x + window->w &&
1161 myc >= window->y &&
1162 myc <= window->y + window->h) {
1163 break;
1164 }
1165 }
1166 }
1167
1168
1169 /* If we didn't find any window, and there are no windows
1170 open, the mouse pointer will definately be within the
1171 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001172 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001173 window = &desktop_window;
1174 }
1175
adamdunkels965e2922003-06-30 20:44:57 +00001176 /* If the mouse pointer moves around outside of the
1177 currently focused window (or dialog), we should not have
1178 any focused widgets in the focused window so we make sure
1179 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001180 if(windows != NULL &&
1181 window != windows &&
1182 windows->focused != NULL){
1183 add_redrawwidget(windows->focused);
1184 windows->focused = NULL;
1185 redraw |= REDRAW_WIDGETS;
1186 }
1187
1188 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001189 /* If the mouse was clicked outside of the current window,
1190 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001191 if(dialog == NULL &&
1192 window != &desktop_window &&
1193 window != windows &&
1194 mouse_clicked) {
1195 /* Bring window to front. */
1196 ctk_window_open(window);
1197 redraw |= REDRAW_ALL;
1198 } else {
1199
adamdunkels965e2922003-06-30 20:44:57 +00001200 /* Find out which widget currently is under the mouse
1201 pointer and give it focus, unless it already has
1202 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001203 mxc = mxc - window->x - 1;
1204 myc = myc - window->y - 1;
1205
adamdunkels965e2922003-06-30 20:44:57 +00001206 /* See if the mouse pointer is on a widget. If so, it
1207 should be selected and, if the button is clicked,
1208 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001209 for(widget = window->active; widget != NULL;
1210 widget = widget->next) {
1211 if(mxc >= widget->x &&
1212 mxc <= widget->x + widget->w &&
1213 (myc == widget->y ||
1214 ((widget->type == CTK_WIDGET_BITMAP ||
1215 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1216 widget->type == CTK_WIDGET_ICON) &&
1217 (myc >= widget->y &&
1218 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1219 break;
1220 }
1221 }
1222
1223
adamdunkels58917a82003-04-18 00:18:38 +00001224 if(mouse_moved &&
1225 (window != &desktop_window ||
1226 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001227 dispatcher_emit(ctk_signal_pointer_move, NULL,
1228 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001229
adamdunkelsb2486562003-04-11 20:22:03 +00001230 if(window->focused != NULL &&
1231 widget != window->focused) {
1232 add_redrawwidget(window->focused);
1233 if(CTK_WIDGET_TYPE(window->focused) ==
1234 CTK_WIDGET_TEXTENTRY) {
1235 ((struct ctk_textentry *)(window->focused))->state =
1236 CTK_TEXTENTRY_NORMAL;
1237 }
1238 window->focused = NULL;
1239 }
1240 redraw |= REDRAW_WIDGETS;
1241 if(widget != NULL) {
1242 select_widget(widget);
1243 }
1244 }
1245
1246 if(mouse_button_changed) {
1247 dispatcher_emit(ctk_signal_pointer_button,
1248 (ek_data_t)mouse_button,
1249 window->owner);
1250 if(mouse_clicked && widget != NULL) {
1251 select_widget(widget);
1252 redraw |= activate(widget);
1253 }
1254 }
1255 }
1256 }
1257 }
adamdunkelsc4902862003-04-09 00:30:45 +00001258 }
1259 }
adamdunkels19a787c2003-04-09 09:22:24 +00001260#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001261
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001262 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001263
1264 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001265
1266 screensaver_timer = 0;
1267
adamdunkelsb2486562003-04-11 20:22:03 +00001268 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001269
1270 if(dialog != NULL) {
1271 window = dialog;
1272 } else if(windows != NULL) {
1273 window = windows;
1274 } else {
1275 window = &desktop_window;
1276 }
1277 widget = window->focused;
1278
1279
1280 if(widget != NULL &&
1281 widget->type == CTK_WIDGET_TEXTENTRY &&
1282 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1283 textentry_input(c, (struct ctk_textentry *)widget);
1284 add_redrawwidget(widget);
1285#if CTK_CONF_MENUS
1286 } else if(menus.open != NULL) {
1287 redraw |= menus_input(c);
1288#endif /* CTK_CONF_MENUS */
1289 } else {
1290 switch(c) {
1291 case CH_CURS_RIGHT:
1292 switch_focus_widget(RIGHT);
1293 break;
1294 case CH_CURS_DOWN:
1295 switch_focus_widget(DOWN);
1296 break;
1297 case CH_CURS_LEFT:
1298 switch_focus_widget(LEFT);
1299 break;
1300 case CH_CURS_UP:
1301 switch_focus_widget(UP);
1302 break;
1303 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001304 if(widget != NULL) {
1305 redraw |= activate(widget);
1306 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001307 break;
1308#if CTK_CONF_MENUS
1309 case CTK_CONF_MENU_KEY:
1310 if(dialog == NULL) {
1311 if(lastmenu == NULL) {
1312 menus.open = menus.menus;
1313 } else {
1314 menus.open = lastmenu;
1315 }
1316 menus.open->active = 0;
1317 redraw |= REDRAW_MENUS;
1318 }
1319 break;
1320#endif /* CTK_CONF_MENUS */
1321 case CTK_CONF_WINDOWSWITCH_KEY:
1322 if(windows != NULL) {
1323 for(window = windows; window->next != NULL;
1324 window = window->next);
1325 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001326 }
1327 break;
1328 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001329 if(widget != NULL &&
1330 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001331 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1332 textentry_input(c, (struct ctk_textentry *)widget);
1333 add_redrawwidget(widget);
1334 } else {
1335 dispatcher_emit(ctk_signal_keypress, (void *)c,
1336 window->owner);
1337 }
1338 break;
1339 }
1340 }
1341
1342 if(redraw & REDRAW_WIDGETS) {
1343 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001344 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001345 }
1346 redraw &= ~REDRAW_WIDGETS;
1347 redraw_widgetptr = 0;
1348 }
1349 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001350#if CTK_CONF_WINDOWMOVE
1351 } else if(mode == CTK_MODE_WINDOWMOVE) {
1352
1353 redraw = 0;
1354
1355 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001356
1357#if CTK_CONF_MOUSE_SUPPORT
1358
1359 /* If the mouse has moved, we move the window as well. */
1360 if(mouse_moved) {
1361
1362 if(window->w + mxc + 2 >= width) {
1363 window->x = width - 2 - window->w;
1364 } else {
1365 window->x = mxc;
1366 }
1367
1368 if(window->h + myc + 2 >= height) {
1369 window->y = height - 2 - window->h;
1370 } else {
1371 window->y = myc;
1372 }
1373 if(window->y > 0) {
1374 --window->y;
1375 }
1376
1377 redraw = REDRAW_ALL;
1378 }
1379
1380 /* Check if the mouse has been clicked, and stop moving the window
1381 if so. */
1382 if(mouse_button_changed &&
1383 mouse_button == 0) {
1384 mode = CTK_MODE_NORMAL;
1385 redraw = REDRAW_ALL;
1386 }
1387#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001388
1389 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1390
1391 screensaver_timer = 0;
1392
1393 c = ctk_arch_getkey();
1394
1395 switch(c) {
1396 case CH_CURS_RIGHT:
1397 ++window->x;
1398 if(window->x + window->w + 1 >= width) {
1399 --window->x;
1400 }
1401 redraw = REDRAW_ALL;
1402 break;
1403 case CH_CURS_LEFT:
1404 if(window->x > 0) {
1405 --window->x;
1406 }
1407 redraw = REDRAW_ALL;
1408 break;
1409 case CH_CURS_DOWN:
1410 ++window->y;
1411 if(window->y + window->h + 2 >= height) {
1412 --window->y;
1413 }
1414 redraw = REDRAW_ALL;
1415 break;
1416 case CH_CURS_UP:
1417 if(window->y > 0) {
1418 --window->y;
1419 }
1420 redraw = REDRAW_ALL;
1421 break;
1422 case CH_ENTER:
1423 case CH_ESC:
1424 mode = CTK_MODE_NORMAL;
1425 redraw = REDRAW_ALL;
1426 break;
1427 }
1428 }
adamdunkelsb2486562003-04-11 20:22:03 +00001429 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001430 do_redraw_all(1, height);
1431 }
adamdunkelsb2486562003-04-11 20:22:03 +00001432 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001433#endif /* CTK_CONF_WINDOWMOVE */
1434 }
adamdunkelsb2486562003-04-11 20:22:03 +00001435
1436 if(redraw & REDRAW_ALL) {
1437 do_redraw_all(1, height);
1438#if CTK_CONF_MENUS
1439 } else if(redraw & REDRAW_MENUPART) {
1440 do_redraw_all(1, maxnitems + 1);
1441 } else if(redraw & REDRAW_MENUS) {
1442 ctk_draw_menus(&menus);
1443#endif /* CTK_CONF_MENUS */
1444 } else if(redraw & REDRAW_FOCUS) {
1445 if(dialog != NULL) {
1446 ctk_window_redraw(dialog);
1447 } else if(windows != NULL) {
1448 ctk_window_redraw(windows);
1449 } else {
1450 ctk_window_redraw(&desktop_window);
1451 }
1452 } else if(redraw & REDRAW_WIDGETS) {
1453 for(i = 0; i < redraw_widgetptr; ++i) {
1454 ctk_widget_redraw(redraw_widgets[i]);
1455 }
1456 }
1457 redraw = 0;
1458 redraw_widgetptr = 0;
1459
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001460}
1461/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001462static
1463DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001464{
adamdunkels78c03dc2003-04-09 13:45:05 +00001465 DISPATCHER_SIGHANDLER_ARGS(s, data);
1466
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001467 if(s == ctk_signal_timer) {
1468 if(mode == CTK_MODE_NORMAL) {
1469 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001470 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001471#if CTK_CONF_SCREENSAVER
1472 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1473 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001474#ifdef CTK_SCREENSAVER_INIT
1475 CTK_SCREENSAVER_INIT();
1476#endif /* CTK_SCREENSAVER_INIT */
1477 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001478#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001479 screensaver_timer = 0;
1480 }
1481 }
1482 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1483 }
1484}
1485/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001486