blob: afc8b7b654e5547490278ded91a51b6d9a670dd3 [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 *
adamdunkels04ec5b42003-08-20 20:55:22 +000035 * $Id: ctk.c,v 1.28 2003/08/20 20:55:22 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000036 *
37 */
38
adamdunkelsd07a5422003-04-05 12:22:35 +000039#include "cc.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000040#include "ek.h"
41#include "dispatcher.h"
42#include "ctk.h"
43#include "ctk-draw.h"
44#include "ctk-conf.h"
adamdunkelsc4902862003-04-09 00:30:45 +000045#include "ctk-mouse.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000046
adamdunkels591724c2003-08-01 00:07:19 +000047#include <string.h>
48
adamdunkelsca9ddcb2003-03-19 14:13:31 +000049static unsigned char height, width;
50
51static unsigned char mode;
52
53static struct ctk_window desktop_window;
54static struct ctk_window *windows;
55static struct ctk_window *dialog;
56
57#if CTK_CONF_MENUS
58static struct ctk_menus menus;
59static struct ctk_menu *lastmenu;
60static struct ctk_menu desktopmenu;
61#endif /* CTK_CONF_MENUS */
62
63#ifndef NULL
64#define NULL (void *)0
65#endif /* NULL */
66
67
68#define REDRAW_NONE 0
69#define REDRAW_ALL 1
70#define REDRAW_FOCUS 2
71#define REDRAW_WIDGETS 4
72#define REDRAW_MENUS 8
73#define REDRAW_MENUPART 16
74
75#define MAX_REDRAWWIDGETS 4
76static unsigned char redraw;
77static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
78static unsigned char redraw_widgetptr;
79static unsigned char maxnitems;
80
81static unsigned char iconx, icony;
adamdunkels591724c2003-08-01 00:07:19 +000082#define ICONX_START (width - 6)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000083#define ICONY_START 0
adamdunkels591724c2003-08-01 00:07:19 +000084#define ICONX_DELTA -16
adamdunkelsca9ddcb2003-03-19 14:13:31 +000085#define ICONY_DELTA 5
adamdunkels591724c2003-08-01 00:07:19 +000086#define ICONY_MAX (height - 5)
adamdunkelsca9ddcb2003-03-19 14:13:31 +000087
adamdunkelsc4902862003-04-09 00:30:45 +000088static void ctk_idle(void);
adamdunkelsca9ddcb2003-03-19 14:13:31 +000089static struct dispatcher_proc p =
adamdunkelscf90b0d2003-08-09 13:34:16 +000090 {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091static ek_id_t ctkid;
92
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093ek_signal_t ctk_signal_keypress,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094 ctk_signal_button_activate,
adamdunkels58917a82003-04-18 00:18:38 +000095 ctk_signal_widget_activate,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096 ctk_signal_button_hover,
adamdunkels58917a82003-04-18 00:18:38 +000097 ctk_signal_widget_select,
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098 ctk_signal_hyperlink_activate,
99 ctk_signal_hyperlink_hover,
100 ctk_signal_menu_activate,
adamdunkelsc4902862003-04-09 00:30:45 +0000101 ctk_signal_window_close,
102 ctk_signal_pointer_move,
adamdunkelsb2486562003-04-11 20:22:03 +0000103 ctk_signal_pointer_button;
adamdunkelsc4902862003-04-09 00:30:45 +0000104
adamdunkels66109622003-04-24 17:17:10 +0000105#if CTK_CONF_SCREENSAVER
adamdunkels9795b2e2003-08-09 23:32:37 +0000106ek_signal_t ctk_signal_screensaver_stop,
107 ctk_signal_screensaver_start;
adamdunkels66109622003-04-24 17:17:10 +0000108#endif /* CTK_CONF_SCREENSAVER */
109
110
adamdunkels19a787c2003-04-09 09:22:24 +0000111#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +0000112unsigned short mouse_x, mouse_y, mouse_button;
adamdunkels19a787c2003-04-09 09:22:24 +0000113#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000114
adamdunkels9795b2e2003-08-09 23:32:37 +0000115static unsigned short screensaver_timer = 0;
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000116unsigned short ctk_screensaver_timeout = (5*60);
adamdunkels9795b2e2003-08-09 23:32:37 +0000117static ek_clock_t start, current;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000118
119#if CTK_CONF_MENUS
120/*-----------------------------------------------------------------------------------*/
121/* make_desktopmenu(void)
122 *
123 * Creates the leftmost menu, "Desktop". Since the desktop menu
124 * contains the list of all open windows, this function will be called
125 * whenever a window is opened or closed.
126 */
127static void
128make_desktopmenu(void)
129{
130 struct ctk_window *w;
131
132 desktopmenu.nitems = 0;
133
134 if(windows == NULL) {
135 ctk_menuitem_add(&desktopmenu, "(No windows)");
136 } else {
137 for(w = windows; w != NULL; w = w->next) {
138 ctk_menuitem_add(&desktopmenu, w->title);
139 }
140 }
141}
142#endif /* CTK_CONF_MENUS */
143/*-----------------------------------------------------------------------------------*/
144/* ctk_init(void)
145 *
146 * Initializes CTK. Must be called before any other CTK function.
147 */
148void
149ctk_init(void)
150{
151 ctkid = dispatcher_start(&p);
152
153 windows = NULL;
154 dialog = NULL;
155
156#if CTK_CONF_MENUS
157 ctk_menu_new(&desktopmenu, "Desktop");
158 make_desktopmenu();
159 menus.menus = menus.desktopmenu = &desktopmenu;
160#endif /* CTK_CONF_MENUS */
161
adamdunkelsb2486562003-04-11 20:22:03 +0000162#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsc4902862003-04-09 00:30:45 +0000163 ctk_mouse_init();
adamdunkelsb2486562003-04-11 20:22:03 +0000164 ctk_mouse_show();
165#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +0000166
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000167 ctk_draw_init();
168
169 height = ctk_draw_height();
170 width = ctk_draw_width();
adamdunkelsb2486562003-04-11 20:22:03 +0000171
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000172 desktop_window.active = NULL;
adamdunkelsb2486562003-04-11 20:22:03 +0000173
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000174 ctk_signal_keypress = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000175
176 ctk_signal_button_activate =
177 ctk_signal_widget_activate = dispatcher_sigalloc();
178
179 ctk_signal_button_hover =
180 ctk_signal_hyperlink_hover =
181 ctk_signal_widget_select = dispatcher_sigalloc();
182
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000183 ctk_signal_hyperlink_activate = dispatcher_sigalloc();
adamdunkels58917a82003-04-18 00:18:38 +0000184
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000185 ctk_signal_menu_activate = dispatcher_sigalloc();
186 ctk_signal_window_close = dispatcher_sigalloc();
adamdunkelsc4902862003-04-09 00:30:45 +0000187
188 ctk_signal_pointer_move = dispatcher_sigalloc();
adamdunkelsb2486562003-04-11 20:22:03 +0000189 ctk_signal_pointer_button = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000190
191
192#if CTK_CONF_SCREENSAVER
193 ctk_signal_screensaver_start = dispatcher_sigalloc();
194 ctk_signal_screensaver_stop = dispatcher_sigalloc();
adamdunkels66109622003-04-24 17:17:10 +0000195#endif /* CTK_CONF_SCREENSAVER */
196
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000197
198 mode = CTK_MODE_NORMAL;
199
200 iconx = ICONX_START;
201 icony = ICONY_START;
adamdunkels965e2922003-06-30 20:44:57 +0000202
203 redraw = REDRAW_ALL;
adamdunkelscf90b0d2003-08-09 13:34:16 +0000204
205 start = ek_clock();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000206}
207/*-----------------------------------------------------------------------------------*/
208/* void ctk_mode_set()
209 */
210void
211ctk_mode_set(unsigned char m) {
212 mode = m;
213}
214/*-----------------------------------------------------------------------------------*/
215unsigned char
216ctk_mode_get(void) {
217 return mode;
218}
219/*-----------------------------------------------------------------------------------*/
220void
adamdunkelsd07a5422003-04-05 12:22:35 +0000221ctk_icon_add(CC_REGISTER_ARG struct ctk_widget *icon,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000222 ek_id_t id)
223{
224#if CTK_CONF_ICONS
225 icon->x = iconx;
226 icon->y = icony;
227 icon->widget.icon.owner = id;
228
229 icony += ICONY_DELTA;
230 if(icony >= ICONY_MAX) {
231 icony = ICONY_START;
232 iconx += ICONX_DELTA;
233 }
234
235 ctk_widget_add(&desktop_window, icon);
236#endif /* CTK_CONF_ICONS */
237}
238/*-----------------------------------------------------------------------------------*/
239void
240ctk_dialog_open(struct ctk_window *d)
241{
242 dialog = d;
adamdunkels591724c2003-08-01 00:07:19 +0000243 redraw |= REDRAW_FOCUS;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000244}
245/*-----------------------------------------------------------------------------------*/
246void
247ctk_dialog_close(void)
248{
249 dialog = NULL;
adamdunkels965e2922003-06-30 20:44:57 +0000250 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000251}
252/*-----------------------------------------------------------------------------------*/
253void
adamdunkelsd07a5422003-04-05 12:22:35 +0000254ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255{
256 struct ctk_window *w2;
257
258 /* Check if already open. */
259 for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
260 if(w2 == NULL) {
261 /* Not open, so we add it at the head of the list of open
262 windows. */
263 w->next = windows;
264 if(windows != NULL) {
265 windows->prev = w;
266 }
267 windows = w;
268 w->prev = NULL;
269 } else {
270 /* Window already open, so we move it to the front of the windows
271 list. */
272 if(w != windows) {
273 if(w->next != NULL) {
274 w->next->prev = w->prev;
275 }
276 if(w->prev != NULL) {
277 w->prev->next = w->next;
278 }
279 w->next = windows;
280 windows->prev = w;
281 windows = w;
282 w->prev = NULL;
283 }
284 }
285
286#if CTK_CONF_MENUS
287 /* Recreate the Desktop menu's window entries.*/
288 make_desktopmenu();
289#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000290
291 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000292}
293/*-----------------------------------------------------------------------------------*/
294void
295ctk_window_close(struct ctk_window *w)
296{
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000297 static struct ctk_window *w2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000298
299 if(w == NULL) {
300 return;
301 }
302
303 /* Check if the window to be closed is the first window on the
304 list. */
305 if(w == windows) {
306 windows = w->next;
307 if(windows != NULL) {
308 windows->prev = NULL;
309 }
310 w->next = w->prev = NULL;
311 } else {
312 /* Otherwise we step through the list until we find the window
313 before the one to be closed. We then redirect its ->next
314 pointer and its ->next->prev. */
adamdunkels3cf116a2003-04-08 19:28:15 +0000315 for(w2 = windows; w2 != NULL && w2->next != w; w2 = w2->next);
316
317 if(w2 == NULL) {
318 /* The window wasn't open, so there is nothing more for us to
319 do. */
320 return;
321 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000322
323 if(w->next != NULL) {
324 w->next->prev = w->prev;
325 }
326 w2->next = w->next;
327
328 w->next = w->prev = NULL;
329 }
330
331#if CTK_CONF_MENUS
332 /* Recreate the Desktop menu's window entries.*/
333 make_desktopmenu();
334#endif /* CTK_CONF_MENUS */
adamdunkels965e2922003-06-30 20:44:57 +0000335 redraw |= REDRAW_ALL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000336}
337/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +0000338static void
339make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000340{
341#if CTK_CONF_WINDOWMOVE
342 CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
343#else
344 CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
345#endif /* CTK_CONF_WINDOWMOVE */
346 CTK_WIDGET_ADD(window, &window->titlebutton);
347
348
349#if CTK_CONF_WINDOWCLOSE
350 CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
351#else
352 CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
353#endif /* CTK_CONF_WINDOWCLOSE */
354 CTK_WIDGET_ADD(window, &window->closebutton);
355}
356/*-----------------------------------------------------------------------------------*/
357void
358ctk_window_clear(struct ctk_window *window)
359{
360 window->active = window->inactive = window->focused = NULL;
361
362 make_windowbuttons(window);
363}
364/*-----------------------------------------------------------------------------------*/
365void
366ctk_menu_add(struct ctk_menu *menu)
367{
368#if CTK_CONF_MENUS
369 struct ctk_menu *m;
370
371 if(lastmenu == NULL) {
372 lastmenu = menu;
373 }
374
375 for(m = menus.menus; m->next != NULL; m = m->next) {
376 if(m == menu) {
377 return;
378 }
379 }
380 m->next = menu;
381 menu->next = NULL;
adamdunkels3af580f2003-08-11 22:27:13 +0000382
383 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000384#endif /* CTK_CONF_MENUS */
385}
386/*-----------------------------------------------------------------------------------*/
387void
388ctk_menu_remove(struct ctk_menu *menu)
389{
390#if CTK_CONF_MENUS
391 struct ctk_menu *m;
392
393 for(m = menus.menus; m->next != NULL; m = m->next) {
394 if(m->next == menu) {
395 m->next = menu->next;
adamdunkels46623032003-08-12 21:12:59 +0000396 if(menu == lastmenu) {
397 lastmenu = NULL;
398 }
399 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000400 return;
401 }
402 }
403#endif /* CTK_CONF_MENUS */
404}
405/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000406static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000407do_redraw_all(unsigned char clipy1, unsigned char clipy2)
408{
409 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000410 static struct ctk_widget *widget;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000411
412 if(mode != CTK_MODE_NORMAL &&
413 mode != CTK_MODE_WINDOWMOVE) {
414 return;
415 }
416
417 ctk_draw_clear(clipy1, clipy2);
418
419 /* Draw widgets in root window */
420 for(widget = desktop_window.active;
421 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000422 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000423 }
424
425 /* Draw windows */
426 if(windows != NULL) {
427 /* Find the last window.*/
428 for(w = windows; w->next != NULL; w = w->next);
429
430 /* Draw the windows from back to front. */
431 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000432 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000433 ctk_draw_window(w, 0, clipy1, clipy2);
434 }
435 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000436 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000437 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
438 }
439
440 /* Draw dialog (if any) */
441 if(dialog != NULL) {
442 ctk_draw_dialog(dialog);
443 }
444
445#if CTK_CONF_MENUS
446 ctk_draw_menus(&menus);
447#endif /* CTK_CONF_MENUS */
448}
449/*-----------------------------------------------------------------------------------*/
450void
adamdunkels965e2922003-06-30 20:44:57 +0000451ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000452{
453 if(DISPATCHER_CURRENT() == ctkid) {
454 if(mode == CTK_MODE_NORMAL ||
455 mode == CTK_MODE_WINDOWMOVE) {
456 do_redraw_all(1, height);
457 }
458 } else {
459 redraw |= REDRAW_ALL;
460 }
461}
462/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000463void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000464ctk_window_redraw(struct ctk_window *w)
465{
466 /* Only redraw the window if it is a dialog or if it is the foremost
467 window. */
468 if(mode != CTK_MODE_NORMAL) {
469 return;
470 }
471
472 if(w == dialog) {
473 ctk_draw_dialog(w);
474 } else if(dialog == NULL &&
475#if CTK_CONF_MENUS
476 menus.open == NULL &&
477#endif /* CTK_CONF_MENUS */
478 windows == w) {
479 ctk_draw_window(w, CTK_FOCUS_WINDOW,
480 0, height);
481 }
482}
483/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000484static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000485window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000486 unsigned char w, unsigned char h,
487 char *title)
488{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000489
490 if(w >= width - 2) {
491 window->x = 0;
492 } else {
493 window->x = (width - w - 2) / 2;
494 }
495 if(h >= height - 3) {
496 window->y = 0;
497 } else {
498 window->y = (height - h - 1) / 2;
499 }
500
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000501 window->w = w;
502 window->h = h;
503 window->title = title;
504 if(title != NULL) {
505 window->titlelen = strlen(title);
506 } else {
507 window->titlelen = 0;
508 }
509 window->next = window->prev = NULL;
510 window->owner = DISPATCHER_CURRENT();
511 window->active = window->inactive = window->focused = NULL;
512}
513/*-----------------------------------------------------------------------------------*/
514void
515ctk_window_new(struct ctk_window *window,
516 unsigned char w, unsigned char h,
517 char *title)
518{
519 window_new(window, w, h, title);
520
521 make_windowbuttons(window);
522}
523/*-----------------------------------------------------------------------------------*/
524void
adamdunkelsd07a5422003-04-05 12:22:35 +0000525ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526 unsigned char w, unsigned char h)
527{
528 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529}
adamdunkels3af580f2003-08-11 22:27:13 +0000530/*-----------------------------------------------------------------------------------*/
531void
adamdunkelsd07a5422003-04-05 12:22:35 +0000532ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000533 char *title)
534{
535#if CTK_CONF_MENUS
536 menu->next = NULL;
537 menu->title = title;
538 menu->titlelen = strlen(title);
539 menu->active = 0;
540 menu->nitems = 0;
541#endif /* CTK_CONF_MENUS */
542}
543/*-----------------------------------------------------------------------------------*/
544unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000545ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000546 char *name)
547{
548#if CTK_CONF_MENUS
549 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
550 return 0;
551 }
552 menu->items[menu->nitems].title = name;
553 menu->items[menu->nitems].titlelen = strlen(name);
554 return menu->nitems++;
555#else
556 return 0;
557#endif /* CTK_CONF_MENUS */
558}
559/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000560static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000561add_redrawwidget(struct ctk_widget *w)
562{
563 static unsigned char i;
564
565 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
566 redraw |= REDRAW_FOCUS;
567 } else {
568 redraw |= REDRAW_WIDGETS;
569 /* Check if it is in the queue already. If so, we don't add it
570 again. */
571 for(i = 0; i < redraw_widgetptr; ++i) {
572 if(redraw_widgets[i] == w) {
573 return;
574 }
575 }
576 redraw_widgets[redraw_widgetptr++] = w;
577 }
578}
579/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000580void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000581ctk_widget_redraw(struct ctk_widget *widget)
582{
583 struct ctk_window *window;
584
adamdunkels9f667f22003-04-16 18:29:19 +0000585 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000586 return;
587 }
588
589 /* If this function isn't called by CTK itself, we only queue the
590 redraw request. */
591 if(DISPATCHER_CURRENT() != ctkid) {
592 redraw |= REDRAW_WIDGETS;
593 add_redrawwidget(widget);
594 } else {
595
596 /* Only redraw widgets that are in the foremost window. If we
597 would allow redrawing widgets in non-focused windows, we would
598 have to redraw all the windows that cover the non-focused
599 window as well, which would lead to flickering.
600
601 Also, we avoid drawing any widgets when the menus are active.
602 */
603
604#if CTK_CONF_MENUS
605 if(menus.open == NULL)
606#endif /* CTK_CONF_MENUS */
607 {
608 window = widget->window;
609 if(window == dialog) {
610 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels47efbc42003-08-07 00:03:26 +0000611 } else if(dialog == NULL &&
adamdunkels9795b2e2003-08-09 23:32:37 +0000612 (window == windows ||
613 window == &desktop_window)) {
adamdunkels66109622003-04-24 17:17:10 +0000614 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000615 }
616 }
617 }
618}
619/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000620void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000621ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
622 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000623{
624 if(widget->type == CTK_WIDGET_LABEL ||
625 widget->type == CTK_WIDGET_SEPARATOR) {
626 widget->next = window->inactive;
627 window->inactive = widget;
628 widget->window = window;
629 } else {
630 widget->next = window->active;
631 window->active = widget;
632 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000633 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000634 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000635 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000636 }
637}
638/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000639unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000640ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000641{
642 return ctk_draw_width();
643}
644/*-----------------------------------------------------------------------------------*/
645unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000646ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000647{
648 return ctk_draw_height();
649}
650/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000651static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000652select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000653{
654 struct ctk_window *window;
655
656 window = focus->window;
657
658 if(focus != window->focused) {
659 window->focused = focus;
660 /* The operation changed the focus, so we emit a "hover" signal
661 for those widgets that support it. */
662
663 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
664 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
665 window->owner);
666 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
667 dispatcher_emit(ctk_signal_button_hover, window->focused,
668 window->owner);
669 }
670
671 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000672
673 dispatcher_emit(ctk_signal_widget_select, focus,
674 focus->window->owner);
675
adamdunkelse0683312003-04-09 09:02:52 +0000676 }
677
678}
679/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000680#define UP 0
681#define DOWN 1
682#define LEFT 2
683#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000684static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000685switch_focus_widget(unsigned char direction)
686{
687 register struct ctk_window *window;
688 register struct ctk_widget *focus;
689 struct ctk_widget *widget;
690
691
692 if(dialog != NULL) {
693 window = dialog;
694 } else {
695 window = windows;
696 }
697
698 /* If there are no windows open, we move focus around between the
699 icons on the root window instead. */
700 if(window == NULL) {
701 window = &desktop_window;
702 }
703
704 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000705 if(focus == NULL) {
706 focus = window->active;
707 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000708 add_redrawwidget(focus);
709
710 if((direction & 1) == 0) {
711 /* Move focus "up" */
712 focus = focus->next;
713 } else {
714 /* Move focus "down" */
715 for(widget = window->active;
716 widget != NULL; widget = widget->next) {
717 if(widget->next == focus) {
718 break;
719 }
720 }
721 focus = widget;
722 if(focus == NULL) {
723 if(window->active != NULL) {
724 for(focus = window->active;
725 focus->next != NULL; focus = focus->next);
726 }
727 }
728 }
729 if(focus == NULL) {
730 focus = window->active;
731 }
adamdunkelse0683312003-04-09 09:02:52 +0000732
adamdunkelsb2486562003-04-11 20:22:03 +0000733 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000734}
735/*-----------------------------------------------------------------------------------*/
736#if CTK_CONF_MENUS
737static void
738switch_open_menu(unsigned char rightleft)
739{
740 struct ctk_menu *menu;
741
742 if(rightleft == 0) {
743 /* Move right */
744 for(menu = menus.menus; menu != NULL; menu = menu->next) {
745 if(menu->next == menus.open) {
746 break;
747 }
748 }
749 lastmenu = menus.open;
750 menus.open = menu;
751 if(menus.open == NULL) {
752 for(menu = menus.menus;
753 menu->next != NULL; menu = menu->next);
754 menus.open = menu;
755 }
756 } else {
757 /* Move to left */
758 lastmenu = menus.open;
759 menus.open = menus.open->next;
760 if(menus.open == NULL) {
761 menus.open = menus.menus;
762 }
763 }
764
adamdunkels66109622003-04-24 17:17:10 +0000765 menus.open->active = 0;
766
767 /* if(menus.open->nitems > maxnitems) {
768 maxnitems = menus.open->nitems;
769 }*/
770
adamdunkels965e2922003-06-30 20:44:57 +0000771 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772}
773/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000774static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000775switch_menu_item(unsigned char updown)
776{
777 register struct ctk_menu *m;
778
779 m = menus.open;
780
781 if(updown == 0) {
782 /* Move up */
783 if(m->active == 0) {
784 m->active = m->nitems - 1;
785 } else {
786 --m->active;
787 if(m->items[m->active].title[0] == '-') {
788 --m->active;
789 }
790 }
791 } else {
792 /* Move down */
793 if(m->active >= m->nitems - 1) {
794 m->active = 0;
795 } else {
796 ++m->active;
797 if(m->items[m->active].title[0] == '-') {
798 ++m->active;
799 }
800 }
801 }
802
803}
804#endif /* CTK_CONF_MENUS */
805/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000806static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000807activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808{
809 static unsigned char len;
810
811 if(w->type == CTK_WIDGET_BUTTON) {
812 if(w == (struct ctk_widget *)&windows->closebutton) {
813#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000814 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000815 ctk_window_close(windows);
816 return REDRAW_ALL;
817#endif /* CTK_CONF_WINDOWCLOSE */
818 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
819#if CTK_CONF_WINDOWCLOSE
820 mode = CTK_MODE_WINDOWMOVE;
821#endif /* CTK_CONF_WINDOWCLOSE */
822 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000823 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000824 w->window->owner);
825 }
826#if CTK_CONF_ICONS
827 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000828 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 w->widget.icon.owner);
830#endif /* CTK_CONF_ICONS */
831 } else if(w->type == CTK_WIDGET_HYPERLINK) {
832 dispatcher_emit(ctk_signal_hyperlink_activate, w,
833 DISPATCHER_BROADCAST);
834 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
835 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
836 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
837 len = strlen(w->widget.textentry.text);
838 if(w->widget.textentry.xpos > len) {
839 w->widget.textentry.xpos = len;
840 }
841 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
842 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +0000843 dispatcher_emit(ctk_signal_widget_activate, w,
844 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 }
846 add_redrawwidget(w);
847 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000848 } else {
849 dispatcher_emit(ctk_signal_widget_activate, w,
850 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851 }
852 return REDRAW_NONE;
853}
854/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000855static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000857 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000859 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000860 static unsigned char len, txpos, typos, tlen;
861
862 txpos = t->xpos;
863 typos = t->ypos;
864 tlen = t->len;
865
866 cptr = &t->text[txpos + typos * tlen];
867
868 switch(c) {
869 case CH_CURS_LEFT:
870 if(txpos > 0) {
871 --txpos;
872 }
873 break;
874
875 case CH_CURS_RIGHT:
876 if(txpos < tlen &&
877 *cptr != 0) {
878 ++txpos;
879 }
880 break;
881
882 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000884 break;
885
886 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000887 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000888 break;
889
890 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +0000891 /* t->state = CTK_TEXTENTRY_NORMAL;*/
892 activate((struct ctk_widget *)t);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000893 break;
894
adamdunkels9795b2e2003-08-09 23:32:37 +0000895 case CTK_CONF_WIDGETDOWN_KEY:
896 t->state = CTK_TEXTENTRY_NORMAL;
897 switch_focus_widget(DOWN);
898 break;
899 case CTK_CONF_WIDGETUP_KEY:
900 t->state = CTK_TEXTENTRY_NORMAL;
901 switch_focus_widget(UP);
902 break;
903
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000904 default:
905 len = tlen - txpos - 1;
906 if(c == CH_DEL) {
907 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +0000908 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000909 *(cptr + len - 1) = 0;
910 --txpos;
911 }
912 } else {
913 if(len > 0) {
914 cptr2 = cptr + len - 1;
915 while(cptr2 + 1 > cptr) {
916 *(cptr2 + 1) = *cptr2;
917 --cptr2;
918 }
919
920 *cptr = c;
921 ++txpos;
922 }
923 }
924 break;
925 }
926
927 t->xpos = txpos;
928 t->ypos = typos;
929}
930/*-----------------------------------------------------------------------------------*/
931#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000932static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000933activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000934{
935 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000936
adamdunkelsb2486562003-04-11 20:22:03 +0000937 lastmenu = menus.open;
938 if(menus.open == &desktopmenu) {
939 for(w = windows; w != NULL; w = w->next) {
940 if(w->title == desktopmenu.items[desktopmenu.active].title) {
941 ctk_window_open(w);
942 menus.open = NULL;
943 return REDRAW_ALL;
944 }
945 }
946 } else {
947 dispatcher_emit(ctk_signal_menu_activate, menus.open,
948 DISPATCHER_BROADCAST);
949 }
950 menus.open = NULL;
951 return REDRAW_MENUPART;
952}
953/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000954static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000955menus_input(ctk_arch_key_t c)
956{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000957
958 if(menus.open->nitems > maxnitems) {
959 maxnitems = menus.open->nitems;
960 }
961
962
963 switch(c) {
964 case CH_CURS_RIGHT:
965 switch_open_menu(1);
966
967 return REDRAW_MENUPART;
968
969 case CH_CURS_DOWN:
970 switch_menu_item(1);
971 return REDRAW_MENUS;
972
973 case CH_CURS_LEFT:
974 switch_open_menu(0);
975 return REDRAW_MENUPART;
976
977 case CH_CURS_UP:
978 switch_menu_item(0);
979 return REDRAW_MENUS;
980
981 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000982 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000983
adamdunkels88ed9c42003-03-28 12:10:09 +0000984 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000985 lastmenu = menus.open;
986 menus.open = NULL;
987 return REDRAW_MENUPART;
988 }
adamdunkelsb2486562003-04-11 20:22:03 +0000989
990 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000991}
992#endif /* CTK_CONF_MENUS */
993/*-----------------------------------------------------------------------------------*/
994static void
adamdunkelscf90b0d2003-08-09 13:34:16 +0000995timer(void)
996{
997 if(mode == CTK_MODE_NORMAL) {
998 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +0000999 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001000#if CTK_CONF_SCREENSAVER
1001 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1002 DISPATCHER_BROADCAST);
1003#ifdef CTK_SCREENSAVER_INIT
1004 CTK_SCREENSAVER_INIT();
1005#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001006
adamdunkelscf90b0d2003-08-09 13:34:16 +00001007#endif /* CTK_CONF_SCREENSAVER */
1008 screensaver_timer = 0;
1009 }
1010 }
1011}
1012/*-----------------------------------------------------------------------------------*/
1013static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001014unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1015{
1016 if(w != NULL) {
1017 redraw |= REDRAW_WIDGETS;
1018 add_redrawwidget(w);
1019 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1020 ((struct ctk_textentry *)w)->state =
1021 CTK_TEXTENTRY_NORMAL;
1022 }
1023 w->window->focused = NULL;
1024 }
1025}
1026/*-----------------------------------------------------------------------------------*/
1027static void
adamdunkelsc4902862003-04-09 00:30:45 +00001028ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001029{
1030 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001031 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001032 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001033 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001034 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001035#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001036 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1037 mouse_clicked;
1038 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001039 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001040
adamdunkels19a787c2003-04-09 09:22:24 +00001041#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001042
1043
1044 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001045
adamdunkels9795b2e2003-08-09 23:32:37 +00001046 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001047 timer();
1048 start = current;
1049 }
1050
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001051#if CTK_CONF_MENUS
1052 if(menus.open != NULL) {
1053 maxnitems = menus.open->nitems;
1054 } else {
1055 maxnitems = 0;
1056 }
1057#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001058
1059#if CTK_CONF_MOUSE_SUPPORT
1060 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1061
1062 /* See if there is any change in the buttons. */
1063 if(ctk_mouse_button() != mouse_button) {
1064 mouse_button = ctk_mouse_button();
1065 mouse_button_changed = 1;
1066 if(mouse_button == 0) {
1067 mouse_clicked = 1;
1068 }
1069 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001070
adamdunkelsb2486562003-04-11 20:22:03 +00001071 /* Check if the mouse pointer has moved. */
1072 if(ctk_mouse_x() != mouse_x ||
1073 ctk_mouse_y() != mouse_y) {
1074 mouse_x = ctk_mouse_x();
1075 mouse_y = ctk_mouse_y();
1076 mouse_moved = 1;
1077 }
1078
1079 mxc = ctk_mouse_xtoc(mouse_x);
1080 myc = ctk_mouse_ytoc(mouse_y);
1081#endif /* CTK_CONF_MOUSE_SUPPORT */
1082
1083
adamdunkels66109622003-04-24 17:17:10 +00001084#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001085 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001086 if(ctk_arch_keyavail()
1087#if CTK_CONF_MOUSE_SUPPORT
1088 || mouse_moved || mouse_button_changed
1089#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001090 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001091 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1092 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001093 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001094 }
adamdunkels66109622003-04-24 17:17:10 +00001095 } else
1096#endif /* CTK_CONF_SCREENSAVER */
1097 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001098#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001099 /* If there is any change in the mouse conditions, find out in
1100 which window the mouse pointer currently is in order to send
1101 the correct signals, or bring a window to focus. */
1102 if(mouse_moved || mouse_button_changed) {
1103 ctk_mouse_show();
1104 screensaver_timer = 0;
1105
1106 if(myc == 0) {
1107 /* Here we should do whatever needs to be done when the mouse
1108 moves around and clicks in the menubar. */
1109 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001110 static unsigned char titlelen;
1111
adamdunkelsb2486562003-04-11 20:22:03 +00001112 /* Find out which menu that the mouse pointer is in. Start
1113 with the ->next menu after the desktop menu. We assume
1114 that the menus start one character from the left screen
1115 side and that the desktop menu is farthest to the
1116 right. */
1117 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001118 for(menu = menus.menus->next;
1119 menu != NULL; menu = menu->next) {
1120 titlelen = menu->titlelen;
1121 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001122 break;
adamdunkelse0683312003-04-09 09:02:52 +00001123 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001124 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001125 }
adamdunkelsb2486562003-04-11 20:22:03 +00001126
1127 /* Also check desktop menu. */
1128 if(mxc >= width - 7 &&
1129 mxc <= width - 1) {
1130 menu = &desktopmenu;
1131 }
1132
1133 menus.open = menu;
1134 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001135 }
adamdunkelse0683312003-04-09 09:02:52 +00001136 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001137 --myc;
1138
1139 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001140 static unsigned char nitems;
1141
adamdunkelsb2486562003-04-11 20:22:03 +00001142 /* Do whatever needs to be done when a menu is open. */
1143
adamdunkelscf90b0d2003-08-09 13:34:16 +00001144 /* First check if the mouse pointer is in the currently open
1145 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001146 if(menus.open == &desktopmenu) {
1147 menux = width - CTK_CONF_MENUWIDTH;
1148 } else {
1149 menux = 1;
1150 for(menu = menus.menus->next; menu != menus.open;
1151 menu = menu->next) {
1152 menux += menu->titlelen;
1153 }
1154 }
1155
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001156 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001157 /* Find out which of the menu items the mouse is pointing
1158 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001159 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1160 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001161 menus.open->active = myc;
1162 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001163 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001164 }
adamdunkelsb2486562003-04-11 20:22:03 +00001165 }
1166
1167 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001168 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001169 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001170 redraw |= activate_menu();
1171 } else {
1172 lastmenu = menus.open;
1173 menus.open = NULL;
1174 redraw |= REDRAW_MENUPART;
1175 }
1176 } else {
1177 redraw |= REDRAW_MENUS;
1178 }
1179 } else {
1180
adamdunkels965e2922003-06-30 20:44:57 +00001181 /* Walk through the windows from top to bottom to see in
1182 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001183 if(dialog != NULL) {
1184 window = dialog;
1185 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001186 for(window = windows; window != NULL;
1187 window = window->next) {
1188
adamdunkelsb2486562003-04-11 20:22:03 +00001189 /* Check if the mouse is within the window. */
1190 if(mxc >= window->x &&
1191 mxc <= window->x + window->w &&
1192 myc >= window->y &&
1193 myc <= window->y + window->h) {
1194 break;
1195 }
1196 }
1197 }
1198
1199
1200 /* If we didn't find any window, and there are no windows
1201 open, the mouse pointer will definately be within the
1202 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001203 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001204 window = &desktop_window;
1205 }
1206
adamdunkels965e2922003-06-30 20:44:57 +00001207 /* If the mouse pointer moves around outside of the
1208 currently focused window (or dialog), we should not have
1209 any focused widgets in the focused window so we make sure
1210 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001211 if(windows != NULL &&
1212 window != windows &&
1213 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001214 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001215 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001216 redraw |= REDRAW_WIDGETS;*/
1217 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001218 }
1219
1220 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001221 /* If the mouse was clicked outside of the current window,
1222 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001223 if(dialog == NULL &&
1224 window != &desktop_window &&
1225 window != windows &&
1226 mouse_clicked) {
1227 /* Bring window to front. */
1228 ctk_window_open(window);
1229 redraw |= REDRAW_ALL;
1230 } else {
1231
adamdunkels965e2922003-06-30 20:44:57 +00001232 /* Find out which widget currently is under the mouse
1233 pointer and give it focus, unless it already has
1234 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001235 mxc = mxc - window->x - 1;
1236 myc = myc - window->y - 1;
1237
adamdunkels965e2922003-06-30 20:44:57 +00001238 /* See if the mouse pointer is on a widget. If so, it
1239 should be selected and, if the button is clicked,
1240 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001241 for(widget = window->active; widget != NULL;
1242 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001243
adamdunkelsb2486562003-04-11 20:22:03 +00001244 if(mxc >= widget->x &&
1245 mxc <= widget->x + widget->w &&
1246 (myc == widget->y ||
1247 ((widget->type == CTK_WIDGET_BITMAP ||
1248 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1249 widget->type == CTK_WIDGET_ICON) &&
1250 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001251 myc <= widget->y +
1252 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001253 break;
1254 }
1255 }
1256
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001257
1258 /* if the mouse is moved in the focused window, we emit
1259 a ctk_signal_pointer_move signal to the owner of the
1260 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001261 if(mouse_moved &&
1262 (window != &desktop_window ||
1263 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001264
adamdunkelsb2486562003-04-11 20:22:03 +00001265 dispatcher_emit(ctk_signal_pointer_move, NULL,
1266 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001267
1268 /* If there was a focused widget that is not below the
1269 mouse pointer, we remove focus from the widget and
1270 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001271 if(window->focused != NULL &&
1272 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001273 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001274 if(CTK_WIDGET_TYPE(window->focused) ==
1275 CTK_WIDGET_TEXTENTRY) {
1276 ((struct ctk_textentry *)(window->focused))->state =
1277 CTK_TEXTENTRY_NORMAL;
1278 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001279 window->focused = NULL;*/
1280 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001281 }
1282 redraw |= REDRAW_WIDGETS;
1283 if(widget != NULL) {
1284 select_widget(widget);
1285 }
1286 }
1287
1288 if(mouse_button_changed) {
1289 dispatcher_emit(ctk_signal_pointer_button,
1290 (ek_data_t)mouse_button,
1291 window->owner);
1292 if(mouse_clicked && widget != NULL) {
1293 select_widget(widget);
1294 redraw |= activate(widget);
1295 }
1296 }
1297 }
1298 }
1299 }
adamdunkelsc4902862003-04-09 00:30:45 +00001300 }
1301 }
adamdunkels19a787c2003-04-09 09:22:24 +00001302#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001303
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001304 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001305
1306 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001307
1308 screensaver_timer = 0;
1309
adamdunkelsb2486562003-04-11 20:22:03 +00001310 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001311
1312 if(dialog != NULL) {
1313 window = dialog;
1314 } else if(windows != NULL) {
1315 window = windows;
1316 } else {
1317 window = &desktop_window;
1318 }
1319 widget = window->focused;
1320
1321
1322 if(widget != NULL &&
1323 widget->type == CTK_WIDGET_TEXTENTRY &&
1324 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1325 textentry_input(c, (struct ctk_textentry *)widget);
1326 add_redrawwidget(widget);
1327#if CTK_CONF_MENUS
1328 } else if(menus.open != NULL) {
1329 redraw |= menus_input(c);
1330#endif /* CTK_CONF_MENUS */
1331 } else {
1332 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001333 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001334 switch_focus_widget(DOWN);
1335 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001336 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001337 switch_focus_widget(UP);
1338 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001339#if CTK_CONF_MENUS
1340 case CTK_CONF_MENU_KEY:
1341 if(dialog == NULL) {
1342 if(lastmenu == NULL) {
1343 menus.open = menus.menus;
1344 } else {
1345 menus.open = lastmenu;
1346 }
1347 menus.open->active = 0;
1348 redraw |= REDRAW_MENUS;
1349 }
1350 break;
1351#endif /* CTK_CONF_MENUS */
1352 case CTK_CONF_WINDOWSWITCH_KEY:
1353 if(windows != NULL) {
1354 for(window = windows; window->next != NULL;
1355 window = window->next);
1356 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001357 }
1358 break;
1359 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001360 if(c == CH_ENTER &&
1361 widget != NULL) {
1362 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001363 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001364 if(widget != NULL &&
1365 widget->type == CTK_WIDGET_TEXTENTRY) {
1366 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1367 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001368 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001369 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001370 /* window->focused = NULL;*/
1371 unfocus_widget(window->focused);
adamdunkels3af580f2003-08-11 22:27:13 +00001372 dispatcher_emit(ctk_signal_keypress, (void *)c,
1373 window->owner);
1374 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001375 }
1376 break;
1377 }
1378 }
1379
1380 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001381 widgetptr = redraw_widgets;
1382 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001383 ctk_widget_redraw(*widgetptr);
1384 *widgetptr = NULL;
1385 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001386 }
1387 redraw &= ~REDRAW_WIDGETS;
1388 redraw_widgetptr = 0;
1389 }
1390 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001391#if CTK_CONF_WINDOWMOVE
1392 } else if(mode == CTK_MODE_WINDOWMOVE) {
1393
1394 redraw = 0;
1395
1396 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001397
1398#if CTK_CONF_MOUSE_SUPPORT
1399
1400 /* If the mouse has moved, we move the window as well. */
1401 if(mouse_moved) {
1402
1403 if(window->w + mxc + 2 >= width) {
1404 window->x = width - 2 - window->w;
1405 } else {
1406 window->x = mxc;
1407 }
1408
1409 if(window->h + myc + 2 >= height) {
1410 window->y = height - 2 - window->h;
1411 } else {
1412 window->y = myc;
1413 }
1414 if(window->y > 0) {
1415 --window->y;
1416 }
1417
1418 redraw = REDRAW_ALL;
1419 }
1420
1421 /* Check if the mouse has been clicked, and stop moving the window
1422 if so. */
1423 if(mouse_button_changed &&
1424 mouse_button == 0) {
1425 mode = CTK_MODE_NORMAL;
1426 redraw = REDRAW_ALL;
1427 }
1428#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001429
1430 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1431
1432 screensaver_timer = 0;
1433
1434 c = ctk_arch_getkey();
1435
1436 switch(c) {
1437 case CH_CURS_RIGHT:
1438 ++window->x;
1439 if(window->x + window->w + 1 >= width) {
1440 --window->x;
1441 }
1442 redraw = REDRAW_ALL;
1443 break;
1444 case CH_CURS_LEFT:
1445 if(window->x > 0) {
1446 --window->x;
1447 }
1448 redraw = REDRAW_ALL;
1449 break;
1450 case CH_CURS_DOWN:
1451 ++window->y;
1452 if(window->y + window->h + 2 >= height) {
1453 --window->y;
1454 }
1455 redraw = REDRAW_ALL;
1456 break;
1457 case CH_CURS_UP:
1458 if(window->y > 0) {
1459 --window->y;
1460 }
1461 redraw = REDRAW_ALL;
1462 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001463 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001464 mode = CTK_MODE_NORMAL;
1465 redraw = REDRAW_ALL;
1466 break;
1467 }
1468 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001469#endif /* CTK_CONF_WINDOWMOVE */
1470 }
adamdunkelsb2486562003-04-11 20:22:03 +00001471
1472 if(redraw & REDRAW_ALL) {
1473 do_redraw_all(1, height);
1474#if CTK_CONF_MENUS
1475 } else if(redraw & REDRAW_MENUPART) {
1476 do_redraw_all(1, maxnitems + 1);
1477 } else if(redraw & REDRAW_MENUS) {
1478 ctk_draw_menus(&menus);
1479#endif /* CTK_CONF_MENUS */
1480 } else if(redraw & REDRAW_FOCUS) {
1481 if(dialog != NULL) {
1482 ctk_window_redraw(dialog);
1483 } else if(windows != NULL) {
1484 ctk_window_redraw(windows);
1485 } else {
1486 ctk_window_redraw(&desktop_window);
1487 }
1488 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001489 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001490 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1491 ctk_widget_redraw(*widgetptr);
1492 *widgetptr = NULL;
1493 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001494 }
1495 }
1496 redraw = 0;
1497 redraw_widgetptr = 0;
1498
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001499}
1500/*-----------------------------------------------------------------------------------*/