blob: 22ed2a5276ce24673b2f2f8504b3dbc3861df0fc [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 *
adamdunkels47efbc42003-08-07 00:03:26 +000035 * $Id: ctk.c,v 1.22 2003/08/07 00:03:26 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);
adamdunkels47efbc42003-08-07 00:03:26 +0000610 } else if(dialog == NULL &&
611 window == windows ||
adamdunkels66109622003-04-24 17:17:10 +0000612 window == &desktop_window) {
613 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000614 }
615 }
616 }
617}
618/*-----------------------------------------------------------------------------------*/
619void
adamdunkelsd07a5422003-04-05 12:22:35 +0000620ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
621 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000622{
623 if(widget->type == CTK_WIDGET_LABEL ||
624 widget->type == CTK_WIDGET_SEPARATOR) {
625 widget->next = window->inactive;
626 window->inactive = widget;
627 widget->window = window;
628 } else {
629 widget->next = window->active;
630 window->active = widget;
631 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000632 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000633 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000634 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000635 }
636}
637/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000638unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000639ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000640{
641 return ctk_draw_width();
642}
643/*-----------------------------------------------------------------------------------*/
644unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000645ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000646{
647 return ctk_draw_height();
648}
649/*-----------------------------------------------------------------------------------*/
adamdunkelse0683312003-04-09 09:02:52 +0000650static void
adamdunkelsb2486562003-04-11 20:22:03 +0000651select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000652{
653 struct ctk_window *window;
654
655 window = focus->window;
656
657 if(focus != window->focused) {
658 window->focused = focus;
659 /* The operation changed the focus, so we emit a "hover" signal
660 for those widgets that support it. */
661
662 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
663 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
664 window->owner);
665 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
666 dispatcher_emit(ctk_signal_button_hover, window->focused,
667 window->owner);
668 }
669
670 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000671
672 dispatcher_emit(ctk_signal_widget_select, focus,
673 focus->window->owner);
674
adamdunkelse0683312003-04-09 09:02:52 +0000675 }
676
677}
678/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000679#define UP 0
680#define DOWN 1
681#define LEFT 2
682#define RIGHT 3
683static void
684switch_focus_widget(unsigned char direction)
685{
686 register struct ctk_window *window;
687 register struct ctk_widget *focus;
688 struct ctk_widget *widget;
689
690
691 if(dialog != NULL) {
692 window = dialog;
693 } else {
694 window = windows;
695 }
696
697 /* If there are no windows open, we move focus around between the
698 icons on the root window instead. */
699 if(window == NULL) {
700 window = &desktop_window;
701 }
702
703 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000704 if(focus == NULL) {
705 focus = window->active;
706 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000707 add_redrawwidget(focus);
708
709 if((direction & 1) == 0) {
710 /* Move focus "up" */
711 focus = focus->next;
712 } else {
713 /* Move focus "down" */
714 for(widget = window->active;
715 widget != NULL; widget = widget->next) {
716 if(widget->next == focus) {
717 break;
718 }
719 }
720 focus = widget;
721 if(focus == NULL) {
722 if(window->active != NULL) {
723 for(focus = window->active;
724 focus->next != NULL; focus = focus->next);
725 }
726 }
727 }
728 if(focus == NULL) {
729 focus = window->active;
730 }
adamdunkelse0683312003-04-09 09:02:52 +0000731
adamdunkelsb2486562003-04-11 20:22:03 +0000732 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000733}
734/*-----------------------------------------------------------------------------------*/
735#if CTK_CONF_MENUS
736static void
737switch_open_menu(unsigned char rightleft)
738{
739 struct ctk_menu *menu;
740
741 if(rightleft == 0) {
742 /* Move right */
743 for(menu = menus.menus; menu != NULL; menu = menu->next) {
744 if(menu->next == menus.open) {
745 break;
746 }
747 }
748 lastmenu = menus.open;
749 menus.open = menu;
750 if(menus.open == NULL) {
751 for(menu = menus.menus;
752 menu->next != NULL; menu = menu->next);
753 menus.open = menu;
754 }
755 } else {
756 /* Move to left */
757 lastmenu = menus.open;
758 menus.open = menus.open->next;
759 if(menus.open == NULL) {
760 menus.open = menus.menus;
761 }
762 }
763
adamdunkels66109622003-04-24 17:17:10 +0000764 menus.open->active = 0;
765
766 /* if(menus.open->nitems > maxnitems) {
767 maxnitems = menus.open->nitems;
768 }*/
769
adamdunkels965e2922003-06-30 20:44:57 +0000770 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000771}
772/*-----------------------------------------------------------------------------------*/
773static void
774switch_menu_item(unsigned char updown)
775{
776 register struct ctk_menu *m;
777
778 m = menus.open;
779
780 if(updown == 0) {
781 /* Move up */
782 if(m->active == 0) {
783 m->active = m->nitems - 1;
784 } else {
785 --m->active;
786 if(m->items[m->active].title[0] == '-') {
787 --m->active;
788 }
789 }
790 } else {
791 /* Move down */
792 if(m->active >= m->nitems - 1) {
793 m->active = 0;
794 } else {
795 ++m->active;
796 if(m->items[m->active].title[0] == '-') {
797 ++m->active;
798 }
799 }
800 }
801
802}
803#endif /* CTK_CONF_MENUS */
804/*-----------------------------------------------------------------------------------*/
805static unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000806activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000807{
808 static unsigned char len;
809
810 if(w->type == CTK_WIDGET_BUTTON) {
811 if(w == (struct ctk_widget *)&windows->closebutton) {
812#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000813 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000814 ctk_window_close(windows);
815 return REDRAW_ALL;
816#endif /* CTK_CONF_WINDOWCLOSE */
817 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
818#if CTK_CONF_WINDOWCLOSE
819 mode = CTK_MODE_WINDOWMOVE;
820#endif /* CTK_CONF_WINDOWCLOSE */
821 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000822 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000823 w->window->owner);
824 }
825#if CTK_CONF_ICONS
826 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000827 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000828 w->widget.icon.owner);
829#endif /* CTK_CONF_ICONS */
830 } else if(w->type == CTK_WIDGET_HYPERLINK) {
831 dispatcher_emit(ctk_signal_hyperlink_activate, w,
832 DISPATCHER_BROADCAST);
833 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
834 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
835 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
836 len = strlen(w->widget.textentry.text);
837 if(w->widget.textentry.xpos > len) {
838 w->widget.textentry.xpos = len;
839 }
840 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
841 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
842 }
843 add_redrawwidget(w);
844 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000845 } else {
846 dispatcher_emit(ctk_signal_widget_activate, w,
847 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000848 }
849 return REDRAW_NONE;
850}
851/*-----------------------------------------------------------------------------------*/
852static void
853textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000854 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000855{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000856 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000857 static unsigned char len, txpos, typos, tlen;
858
859 txpos = t->xpos;
860 typos = t->ypos;
861 tlen = t->len;
862
863 cptr = &t->text[txpos + typos * tlen];
864
865 switch(c) {
866 case CH_CURS_LEFT:
867 if(txpos > 0) {
868 --txpos;
869 }
870 break;
871
872 case CH_CURS_RIGHT:
873 if(txpos < tlen &&
874 *cptr != 0) {
875 ++txpos;
876 }
877 break;
878
879 case CH_CURS_UP:
880#if CTK_CONF_TEXTENTRY_MULTILINE
881 if(t->h == 1) {
882 txpos = 0;
883 } else {
884 if(typos > 0) {
885 --typos;
886 } else {
887 t->state = CTK_TEXTENTRY_NORMAL;
888 }
889 }
890#else
891 txpos = 0;
892#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
893 break;
894
895 case CH_CURS_DOWN:
896#if CTK_CONF_TEXTENTRY_MULTILINE
897 if(t->h == 1) {
898 txpos = strlen(t->text);
899 } else {
900 if(typos < t->h - 1) {
901 ++typos;
902 } else {
903 t->state = CTK_TEXTENTRY_NORMAL;
904 }
905 }
906#else
907 txpos = strlen(t->text);
908#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
909 break;
910
911 case CH_ENTER:
912#if CTK_CONF_TEXTENTRY_MULTILINE
913 if(t->h == 1) {
914 t->state = CTK_TEXTENTRY_NORMAL;
915 } else {
916 if(typos < t->h - 1) {
917 ++typos;
918 txpos = 0;
919 } else {
920 t->state = CTK_TEXTENTRY_NORMAL;
921 }
922 }
923#else
924 t->state = CTK_TEXTENTRY_NORMAL;
925#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
926 break;
927
928 default:
929 len = tlen - txpos - 1;
930 if(c == CH_DEL) {
931 if(txpos > 0 && len > 0) {
932 strncpy(cptr - 1, cptr,
933 len);
934 *(cptr + len - 1) = 0;
935 --txpos;
936 }
937 } else {
938 if(len > 0) {
939 cptr2 = cptr + len - 1;
940 while(cptr2 + 1 > cptr) {
941 *(cptr2 + 1) = *cptr2;
942 --cptr2;
943 }
944
945 *cptr = c;
946 ++txpos;
947 }
948 }
949 break;
950 }
951
952 t->xpos = txpos;
953 t->ypos = typos;
954}
955/*-----------------------------------------------------------------------------------*/
956#if CTK_CONF_MENUS
957static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000958activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000959{
960 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000961
962 lastmenu = menus.open;
963 if(menus.open == &desktopmenu) {
964 for(w = windows; w != NULL; w = w->next) {
965 if(w->title == desktopmenu.items[desktopmenu.active].title) {
966 ctk_window_open(w);
967 menus.open = NULL;
968 return REDRAW_ALL;
969 }
970 }
971 } else {
972 dispatcher_emit(ctk_signal_menu_activate, menus.open,
973 DISPATCHER_BROADCAST);
974 }
975 menus.open = NULL;
976 return REDRAW_MENUPART;
977}
978/*-----------------------------------------------------------------------------------*/
979static unsigned char
980menus_input(ctk_arch_key_t c)
981{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000982
983 if(menus.open->nitems > maxnitems) {
984 maxnitems = menus.open->nitems;
985 }
986
987
988 switch(c) {
989 case CH_CURS_RIGHT:
990 switch_open_menu(1);
991
992 return REDRAW_MENUPART;
993
994 case CH_CURS_DOWN:
995 switch_menu_item(1);
996 return REDRAW_MENUS;
997
998 case CH_CURS_LEFT:
999 switch_open_menu(0);
1000 return REDRAW_MENUPART;
1001
1002 case CH_CURS_UP:
1003 switch_menu_item(0);
1004 return REDRAW_MENUS;
1005
1006 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +00001007 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001008
adamdunkels88ed9c42003-03-28 12:10:09 +00001009 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001010 lastmenu = menus.open;
1011 menus.open = NULL;
1012 return REDRAW_MENUPART;
1013 }
adamdunkelsb2486562003-04-11 20:22:03 +00001014
1015 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001016}
1017#endif /* CTK_CONF_MENUS */
1018/*-----------------------------------------------------------------------------------*/
1019static void
adamdunkelsc4902862003-04-09 00:30:45 +00001020ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001021{
1022 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001023 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001024 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001025 register struct ctk_widget *widget;
1026#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001027 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1028 mouse_clicked;
1029 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001030 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001031
adamdunkels19a787c2003-04-09 09:22:24 +00001032#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001033
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001034#if CTK_CONF_MENUS
1035 if(menus.open != NULL) {
1036 maxnitems = menus.open->nitems;
1037 } else {
1038 maxnitems = 0;
1039 }
1040#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001041
1042#if CTK_CONF_MOUSE_SUPPORT
1043 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1044
1045 /* See if there is any change in the buttons. */
1046 if(ctk_mouse_button() != mouse_button) {
1047 mouse_button = ctk_mouse_button();
1048 mouse_button_changed = 1;
1049 if(mouse_button == 0) {
1050 mouse_clicked = 1;
1051 }
1052 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001053
adamdunkelsb2486562003-04-11 20:22:03 +00001054 /* Check if the mouse pointer has moved. */
1055 if(ctk_mouse_x() != mouse_x ||
1056 ctk_mouse_y() != mouse_y) {
1057 mouse_x = ctk_mouse_x();
1058 mouse_y = ctk_mouse_y();
1059 mouse_moved = 1;
1060 }
1061
1062 mxc = ctk_mouse_xtoc(mouse_x);
1063 myc = ctk_mouse_ytoc(mouse_y);
1064#endif /* CTK_CONF_MOUSE_SUPPORT */
1065
1066
adamdunkels66109622003-04-24 17:17:10 +00001067#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001068 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001069 if(ctk_arch_keyavail()
1070#if CTK_CONF_MOUSE_SUPPORT
1071 || mouse_moved || mouse_button_changed
1072#endif /* CTK_CONF_MOUSE_SUPPORT */
1073 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001074 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1075 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001076 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077 }
adamdunkels66109622003-04-24 17:17:10 +00001078 } else
1079#endif /* CTK_CONF_SCREENSAVER */
1080 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001081#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001082 /* If there is any change in the mouse conditions, find out in
1083 which window the mouse pointer currently is in order to send
1084 the correct signals, or bring a window to focus. */
1085 if(mouse_moved || mouse_button_changed) {
1086 ctk_mouse_show();
1087 screensaver_timer = 0;
1088
1089 if(myc == 0) {
1090 /* Here we should do whatever needs to be done when the mouse
1091 moves around and clicks in the menubar. */
1092 if(mouse_clicked) {
1093 /* Find out which menu that the mouse pointer is in. Start
1094 with the ->next menu after the desktop menu. We assume
1095 that the menus start one character from the left screen
1096 side and that the desktop menu is farthest to the
1097 right. */
1098 menux = 1;
1099 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1100 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1101 break;
adamdunkelse0683312003-04-09 09:02:52 +00001102 }
adamdunkelsb2486562003-04-11 20:22:03 +00001103 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001104 }
adamdunkelsb2486562003-04-11 20:22:03 +00001105
1106 /* Also check desktop menu. */
1107 if(mxc >= width - 7 &&
1108 mxc <= width - 1) {
1109 menu = &desktopmenu;
1110 }
1111
1112 menus.open = menu;
1113 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001114 }
adamdunkelse0683312003-04-09 09:02:52 +00001115 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001116 --myc;
1117
1118 if(menus.open != NULL) {
1119 /* Do whatever needs to be done when a menu is open. */
1120
1121 if(menus.open == &desktopmenu) {
1122 menux = width - CTK_CONF_MENUWIDTH;
1123 } else {
1124 menux = 1;
1125 for(menu = menus.menus->next; menu != menus.open;
1126 menu = menu->next) {
1127 menux += menu->titlelen;
1128 }
1129 }
1130
1131 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001132 if(myc <= menus.open->nitems) {
1133 menus.open->active = myc;
1134 } else {
1135 menus.open->active = menus.open->nitems - 1;
1136 }
adamdunkelsb2486562003-04-11 20:22:03 +00001137 }
1138
1139 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001140 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1141 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001142 redraw |= activate_menu();
1143 } else {
1144 lastmenu = menus.open;
1145 menus.open = NULL;
1146 redraw |= REDRAW_MENUPART;
1147 }
1148 } else {
1149 redraw |= REDRAW_MENUS;
1150 }
1151 } else {
1152
adamdunkels965e2922003-06-30 20:44:57 +00001153 /* Walk through the windows from top to bottom to see in
1154 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001155 if(dialog != NULL) {
1156 window = dialog;
1157 } else {
1158 for(window = windows; window != NULL; window = window->next) {
1159 /* Check if the mouse is within the window. */
1160 if(mxc >= window->x &&
1161 mxc <= window->x + window->w &&
1162 myc >= window->y &&
1163 myc <= window->y + window->h) {
1164 break;
1165 }
1166 }
1167 }
1168
1169
1170 /* If we didn't find any window, and there are no windows
1171 open, the mouse pointer will definately be within the
1172 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001173 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001174 window = &desktop_window;
1175 }
1176
adamdunkels965e2922003-06-30 20:44:57 +00001177 /* If the mouse pointer moves around outside of the
1178 currently focused window (or dialog), we should not have
1179 any focused widgets in the focused window so we make sure
1180 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001181 if(windows != NULL &&
1182 window != windows &&
1183 windows->focused != NULL){
1184 add_redrawwidget(windows->focused);
1185 windows->focused = NULL;
1186 redraw |= REDRAW_WIDGETS;
1187 }
1188
1189 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001190 /* If the mouse was clicked outside of the current window,
1191 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001192 if(dialog == NULL &&
1193 window != &desktop_window &&
1194 window != windows &&
1195 mouse_clicked) {
1196 /* Bring window to front. */
1197 ctk_window_open(window);
1198 redraw |= REDRAW_ALL;
1199 } else {
1200
adamdunkels965e2922003-06-30 20:44:57 +00001201 /* Find out which widget currently is under the mouse
1202 pointer and give it focus, unless it already has
1203 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001204 mxc = mxc - window->x - 1;
1205 myc = myc - window->y - 1;
1206
adamdunkels965e2922003-06-30 20:44:57 +00001207 /* See if the mouse pointer is on a widget. If so, it
1208 should be selected and, if the button is clicked,
1209 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001210 for(widget = window->active; widget != NULL;
1211 widget = widget->next) {
1212 if(mxc >= widget->x &&
1213 mxc <= widget->x + widget->w &&
1214 (myc == widget->y ||
1215 ((widget->type == CTK_WIDGET_BITMAP ||
1216 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1217 widget->type == CTK_WIDGET_ICON) &&
1218 (myc >= widget->y &&
1219 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1220 break;
1221 }
1222 }
1223
1224
adamdunkels58917a82003-04-18 00:18:38 +00001225 if(mouse_moved &&
1226 (window != &desktop_window ||
1227 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001228 dispatcher_emit(ctk_signal_pointer_move, NULL,
1229 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001230
adamdunkelsb2486562003-04-11 20:22:03 +00001231 if(window->focused != NULL &&
1232 widget != window->focused) {
1233 add_redrawwidget(window->focused);
1234 if(CTK_WIDGET_TYPE(window->focused) ==
1235 CTK_WIDGET_TEXTENTRY) {
1236 ((struct ctk_textentry *)(window->focused))->state =
1237 CTK_TEXTENTRY_NORMAL;
1238 }
1239 window->focused = NULL;
1240 }
1241 redraw |= REDRAW_WIDGETS;
1242 if(widget != NULL) {
1243 select_widget(widget);
1244 }
1245 }
1246
1247 if(mouse_button_changed) {
1248 dispatcher_emit(ctk_signal_pointer_button,
1249 (ek_data_t)mouse_button,
1250 window->owner);
1251 if(mouse_clicked && widget != NULL) {
1252 select_widget(widget);
1253 redraw |= activate(widget);
1254 }
1255 }
1256 }
1257 }
1258 }
adamdunkelsc4902862003-04-09 00:30:45 +00001259 }
1260 }
adamdunkels19a787c2003-04-09 09:22:24 +00001261#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001262
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001263 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001264
1265 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266
1267 screensaver_timer = 0;
1268
adamdunkelsb2486562003-04-11 20:22:03 +00001269 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001270
1271 if(dialog != NULL) {
1272 window = dialog;
1273 } else if(windows != NULL) {
1274 window = windows;
1275 } else {
1276 window = &desktop_window;
1277 }
1278 widget = window->focused;
1279
1280
1281 if(widget != NULL &&
1282 widget->type == CTK_WIDGET_TEXTENTRY &&
1283 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1284 textentry_input(c, (struct ctk_textentry *)widget);
1285 add_redrawwidget(widget);
1286#if CTK_CONF_MENUS
1287 } else if(menus.open != NULL) {
1288 redraw |= menus_input(c);
1289#endif /* CTK_CONF_MENUS */
1290 } else {
1291 switch(c) {
1292 case CH_CURS_RIGHT:
1293 switch_focus_widget(RIGHT);
1294 break;
1295 case CH_CURS_DOWN:
1296 switch_focus_widget(DOWN);
1297 break;
1298 case CH_CURS_LEFT:
1299 switch_focus_widget(LEFT);
1300 break;
1301 case CH_CURS_UP:
1302 switch_focus_widget(UP);
1303 break;
1304 case CH_ENTER:
adamdunkels9f667f22003-04-16 18:29:19 +00001305 if(widget != NULL) {
1306 redraw |= activate(widget);
1307 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001308 break;
1309#if CTK_CONF_MENUS
1310 case CTK_CONF_MENU_KEY:
1311 if(dialog == NULL) {
1312 if(lastmenu == NULL) {
1313 menus.open = menus.menus;
1314 } else {
1315 menus.open = lastmenu;
1316 }
1317 menus.open->active = 0;
1318 redraw |= REDRAW_MENUS;
1319 }
1320 break;
1321#endif /* CTK_CONF_MENUS */
1322 case CTK_CONF_WINDOWSWITCH_KEY:
1323 if(windows != NULL) {
1324 for(window = windows; window->next != NULL;
1325 window = window->next);
1326 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001327 }
1328 break;
1329 default:
adamdunkelsb51799e2003-04-15 21:23:33 +00001330 if(widget != NULL &&
1331 widget->type == CTK_WIDGET_TEXTENTRY) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001332 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1333 textentry_input(c, (struct ctk_textentry *)widget);
1334 add_redrawwidget(widget);
1335 } else {
1336 dispatcher_emit(ctk_signal_keypress, (void *)c,
1337 window->owner);
1338 }
1339 break;
1340 }
1341 }
1342
1343 if(redraw & REDRAW_WIDGETS) {
1344 for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkels9f667f22003-04-16 18:29:19 +00001345 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001346 }
1347 redraw &= ~REDRAW_WIDGETS;
1348 redraw_widgetptr = 0;
1349 }
1350 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001351#if CTK_CONF_WINDOWMOVE
1352 } else if(mode == CTK_MODE_WINDOWMOVE) {
1353
1354 redraw = 0;
1355
1356 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001357
1358#if CTK_CONF_MOUSE_SUPPORT
1359
1360 /* If the mouse has moved, we move the window as well. */
1361 if(mouse_moved) {
1362
1363 if(window->w + mxc + 2 >= width) {
1364 window->x = width - 2 - window->w;
1365 } else {
1366 window->x = mxc;
1367 }
1368
1369 if(window->h + myc + 2 >= height) {
1370 window->y = height - 2 - window->h;
1371 } else {
1372 window->y = myc;
1373 }
1374 if(window->y > 0) {
1375 --window->y;
1376 }
1377
1378 redraw = REDRAW_ALL;
1379 }
1380
1381 /* Check if the mouse has been clicked, and stop moving the window
1382 if so. */
1383 if(mouse_button_changed &&
1384 mouse_button == 0) {
1385 mode = CTK_MODE_NORMAL;
1386 redraw = REDRAW_ALL;
1387 }
1388#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001389
1390 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1391
1392 screensaver_timer = 0;
1393
1394 c = ctk_arch_getkey();
1395
1396 switch(c) {
1397 case CH_CURS_RIGHT:
1398 ++window->x;
1399 if(window->x + window->w + 1 >= width) {
1400 --window->x;
1401 }
1402 redraw = REDRAW_ALL;
1403 break;
1404 case CH_CURS_LEFT:
1405 if(window->x > 0) {
1406 --window->x;
1407 }
1408 redraw = REDRAW_ALL;
1409 break;
1410 case CH_CURS_DOWN:
1411 ++window->y;
1412 if(window->y + window->h + 2 >= height) {
1413 --window->y;
1414 }
1415 redraw = REDRAW_ALL;
1416 break;
1417 case CH_CURS_UP:
1418 if(window->y > 0) {
1419 --window->y;
1420 }
1421 redraw = REDRAW_ALL;
1422 break;
1423 case CH_ENTER:
1424 case CH_ESC:
1425 mode = CTK_MODE_NORMAL;
1426 redraw = REDRAW_ALL;
1427 break;
1428 }
1429 }
adamdunkelsb2486562003-04-11 20:22:03 +00001430 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001431 do_redraw_all(1, height);
1432 }
adamdunkelsb2486562003-04-11 20:22:03 +00001433 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001434#endif /* CTK_CONF_WINDOWMOVE */
1435 }
adamdunkelsb2486562003-04-11 20:22:03 +00001436
1437 if(redraw & REDRAW_ALL) {
1438 do_redraw_all(1, height);
1439#if CTK_CONF_MENUS
1440 } else if(redraw & REDRAW_MENUPART) {
1441 do_redraw_all(1, maxnitems + 1);
1442 } else if(redraw & REDRAW_MENUS) {
1443 ctk_draw_menus(&menus);
1444#endif /* CTK_CONF_MENUS */
1445 } else if(redraw & REDRAW_FOCUS) {
1446 if(dialog != NULL) {
1447 ctk_window_redraw(dialog);
1448 } else if(windows != NULL) {
1449 ctk_window_redraw(windows);
1450 } else {
1451 ctk_window_redraw(&desktop_window);
1452 }
1453 } else if(redraw & REDRAW_WIDGETS) {
1454 for(i = 0; i < redraw_widgetptr; ++i) {
1455 ctk_widget_redraw(redraw_widgets[i]);
1456 }
1457 }
1458 redraw = 0;
1459 redraw_widgetptr = 0;
1460
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001461}
1462/*-----------------------------------------------------------------------------------*/
adamdunkels78c03dc2003-04-09 13:45:05 +00001463static
1464DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001465{
adamdunkels78c03dc2003-04-09 13:45:05 +00001466 DISPATCHER_SIGHANDLER_ARGS(s, data);
1467
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001468 if(s == ctk_signal_timer) {
1469 if(mode == CTK_MODE_NORMAL) {
1470 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001471 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001472#if CTK_CONF_SCREENSAVER
1473 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1474 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001475#ifdef CTK_SCREENSAVER_INIT
1476 CTK_SCREENSAVER_INIT();
1477#endif /* CTK_SCREENSAVER_INIT */
1478 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001479#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001480 screensaver_timer = 0;
1481 }
1482 }
1483 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1484 }
1485}
1486/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001487