blob: 76a1a6260e7bb67c52fe45456ccd0d293c0e3f66 [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 *
adamdunkels4dd8eeb2003-08-15 18:49:22 +000035 * $Id: ctk.c,v 1.27 2003/08/15 18:49: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;
843 }
844 add_redrawwidget(w);
845 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000846 } else {
847 dispatcher_emit(ctk_signal_widget_activate, w,
848 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849 }
850 return REDRAW_NONE;
851}
852/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000853static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000855 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000857 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858 static unsigned char len, txpos, typos, tlen;
859
860 txpos = t->xpos;
861 typos = t->ypos;
862 tlen = t->len;
863
864 cptr = &t->text[txpos + typos * tlen];
865
866 switch(c) {
867 case CH_CURS_LEFT:
868 if(txpos > 0) {
869 --txpos;
870 }
871 break;
872
873 case CH_CURS_RIGHT:
874 if(txpos < tlen &&
875 *cptr != 0) {
876 ++txpos;
877 }
878 break;
879
880 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000881 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882 break;
883
884 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000885 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000886 break;
887
888 case CH_ENTER:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000889 t->state = CTK_TEXTENTRY_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000890 break;
891
adamdunkels9795b2e2003-08-09 23:32:37 +0000892 case CTK_CONF_WIDGETDOWN_KEY:
893 t->state = CTK_TEXTENTRY_NORMAL;
894 switch_focus_widget(DOWN);
895 break;
896 case CTK_CONF_WIDGETUP_KEY:
897 t->state = CTK_TEXTENTRY_NORMAL;
898 switch_focus_widget(UP);
899 break;
900
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000901 default:
902 len = tlen - txpos - 1;
903 if(c == CH_DEL) {
904 if(txpos > 0 && len > 0) {
905 strncpy(cptr - 1, cptr,
906 len);
907 *(cptr + len - 1) = 0;
908 --txpos;
909 }
910 } else {
911 if(len > 0) {
912 cptr2 = cptr + len - 1;
913 while(cptr2 + 1 > cptr) {
914 *(cptr2 + 1) = *cptr2;
915 --cptr2;
916 }
917
918 *cptr = c;
919 ++txpos;
920 }
921 }
922 break;
923 }
924
925 t->xpos = txpos;
926 t->ypos = typos;
927}
928/*-----------------------------------------------------------------------------------*/
929#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000930static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000931activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000932{
933 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000934
adamdunkelsb2486562003-04-11 20:22:03 +0000935 lastmenu = menus.open;
936 if(menus.open == &desktopmenu) {
937 for(w = windows; w != NULL; w = w->next) {
938 if(w->title == desktopmenu.items[desktopmenu.active].title) {
939 ctk_window_open(w);
940 menus.open = NULL;
941 return REDRAW_ALL;
942 }
943 }
944 } else {
945 dispatcher_emit(ctk_signal_menu_activate, menus.open,
946 DISPATCHER_BROADCAST);
947 }
948 menus.open = NULL;
949 return REDRAW_MENUPART;
950}
951/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000952static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000953menus_input(ctk_arch_key_t c)
954{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000955
956 if(menus.open->nitems > maxnitems) {
957 maxnitems = menus.open->nitems;
958 }
959
960
961 switch(c) {
962 case CH_CURS_RIGHT:
963 switch_open_menu(1);
964
965 return REDRAW_MENUPART;
966
967 case CH_CURS_DOWN:
968 switch_menu_item(1);
969 return REDRAW_MENUS;
970
971 case CH_CURS_LEFT:
972 switch_open_menu(0);
973 return REDRAW_MENUPART;
974
975 case CH_CURS_UP:
976 switch_menu_item(0);
977 return REDRAW_MENUS;
978
979 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000980 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000981
adamdunkels88ed9c42003-03-28 12:10:09 +0000982 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000983 lastmenu = menus.open;
984 menus.open = NULL;
985 return REDRAW_MENUPART;
986 }
adamdunkelsb2486562003-04-11 20:22:03 +0000987
988 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000989}
990#endif /* CTK_CONF_MENUS */
991/*-----------------------------------------------------------------------------------*/
992static void
adamdunkelscf90b0d2003-08-09 13:34:16 +0000993timer(void)
994{
995 if(mode == CTK_MODE_NORMAL) {
996 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +0000997 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +0000998#if CTK_CONF_SCREENSAVER
999 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1000 DISPATCHER_BROADCAST);
1001#ifdef CTK_SCREENSAVER_INIT
1002 CTK_SCREENSAVER_INIT();
1003#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001004
adamdunkelscf90b0d2003-08-09 13:34:16 +00001005#endif /* CTK_CONF_SCREENSAVER */
1006 screensaver_timer = 0;
1007 }
1008 }
1009}
1010/*-----------------------------------------------------------------------------------*/
1011static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001012unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1013{
1014 if(w != NULL) {
1015 redraw |= REDRAW_WIDGETS;
1016 add_redrawwidget(w);
1017 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1018 ((struct ctk_textentry *)w)->state =
1019 CTK_TEXTENTRY_NORMAL;
1020 }
1021 w->window->focused = NULL;
1022 }
1023}
1024/*-----------------------------------------------------------------------------------*/
1025static void
adamdunkelsc4902862003-04-09 00:30:45 +00001026ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001027{
1028 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001029 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001030 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001031 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001032 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001033#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001034 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1035 mouse_clicked;
1036 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001037 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001038
adamdunkels19a787c2003-04-09 09:22:24 +00001039#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001040
1041
1042 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001043
adamdunkels9795b2e2003-08-09 23:32:37 +00001044 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001045 timer();
1046 start = current;
1047 }
1048
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001049#if CTK_CONF_MENUS
1050 if(menus.open != NULL) {
1051 maxnitems = menus.open->nitems;
1052 } else {
1053 maxnitems = 0;
1054 }
1055#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001056
1057#if CTK_CONF_MOUSE_SUPPORT
1058 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1059
1060 /* See if there is any change in the buttons. */
1061 if(ctk_mouse_button() != mouse_button) {
1062 mouse_button = ctk_mouse_button();
1063 mouse_button_changed = 1;
1064 if(mouse_button == 0) {
1065 mouse_clicked = 1;
1066 }
1067 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001068
adamdunkelsb2486562003-04-11 20:22:03 +00001069 /* Check if the mouse pointer has moved. */
1070 if(ctk_mouse_x() != mouse_x ||
1071 ctk_mouse_y() != mouse_y) {
1072 mouse_x = ctk_mouse_x();
1073 mouse_y = ctk_mouse_y();
1074 mouse_moved = 1;
1075 }
1076
1077 mxc = ctk_mouse_xtoc(mouse_x);
1078 myc = ctk_mouse_ytoc(mouse_y);
1079#endif /* CTK_CONF_MOUSE_SUPPORT */
1080
1081
adamdunkels66109622003-04-24 17:17:10 +00001082#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001083 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001084 if(ctk_arch_keyavail()
1085#if CTK_CONF_MOUSE_SUPPORT
1086 || mouse_moved || mouse_button_changed
1087#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001088 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001089 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1090 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001091 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001092 }
adamdunkels66109622003-04-24 17:17:10 +00001093 } else
1094#endif /* CTK_CONF_SCREENSAVER */
1095 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001096#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001097 /* If there is any change in the mouse conditions, find out in
1098 which window the mouse pointer currently is in order to send
1099 the correct signals, or bring a window to focus. */
1100 if(mouse_moved || mouse_button_changed) {
1101 ctk_mouse_show();
1102 screensaver_timer = 0;
1103
1104 if(myc == 0) {
1105 /* Here we should do whatever needs to be done when the mouse
1106 moves around and clicks in the menubar. */
1107 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001108 static unsigned char titlelen;
1109
adamdunkelsb2486562003-04-11 20:22:03 +00001110 /* Find out which menu that the mouse pointer is in. Start
1111 with the ->next menu after the desktop menu. We assume
1112 that the menus start one character from the left screen
1113 side and that the desktop menu is farthest to the
1114 right. */
1115 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001116 for(menu = menus.menus->next;
1117 menu != NULL; menu = menu->next) {
1118 titlelen = menu->titlelen;
1119 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001120 break;
adamdunkelse0683312003-04-09 09:02:52 +00001121 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001122 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001123 }
adamdunkelsb2486562003-04-11 20:22:03 +00001124
1125 /* Also check desktop menu. */
1126 if(mxc >= width - 7 &&
1127 mxc <= width - 1) {
1128 menu = &desktopmenu;
1129 }
1130
1131 menus.open = menu;
1132 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001133 }
adamdunkelse0683312003-04-09 09:02:52 +00001134 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001135 --myc;
1136
1137 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001138 static unsigned char nitems;
1139
adamdunkelsb2486562003-04-11 20:22:03 +00001140 /* Do whatever needs to be done when a menu is open. */
1141
adamdunkelscf90b0d2003-08-09 13:34:16 +00001142 /* First check if the mouse pointer is in the currently open
1143 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001144 if(menus.open == &desktopmenu) {
1145 menux = width - CTK_CONF_MENUWIDTH;
1146 } else {
1147 menux = 1;
1148 for(menu = menus.menus->next; menu != menus.open;
1149 menu = menu->next) {
1150 menux += menu->titlelen;
1151 }
1152 }
1153
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001154 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001155 /* Find out which of the menu items the mouse is pointing
1156 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001157 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1158 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001159 menus.open->active = myc;
1160 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001161 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001162 }
adamdunkelsb2486562003-04-11 20:22:03 +00001163 }
1164
1165 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001166 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001167 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001168 redraw |= activate_menu();
1169 } else {
1170 lastmenu = menus.open;
1171 menus.open = NULL;
1172 redraw |= REDRAW_MENUPART;
1173 }
1174 } else {
1175 redraw |= REDRAW_MENUS;
1176 }
1177 } else {
1178
adamdunkels965e2922003-06-30 20:44:57 +00001179 /* Walk through the windows from top to bottom to see in
1180 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001181 if(dialog != NULL) {
1182 window = dialog;
1183 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001184 for(window = windows; window != NULL;
1185 window = window->next) {
1186
adamdunkelsb2486562003-04-11 20:22:03 +00001187 /* Check if the mouse is within the window. */
1188 if(mxc >= window->x &&
1189 mxc <= window->x + window->w &&
1190 myc >= window->y &&
1191 myc <= window->y + window->h) {
1192 break;
1193 }
1194 }
1195 }
1196
1197
1198 /* If we didn't find any window, and there are no windows
1199 open, the mouse pointer will definately be within the
1200 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001201 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001202 window = &desktop_window;
1203 }
1204
adamdunkels965e2922003-06-30 20:44:57 +00001205 /* If the mouse pointer moves around outside of the
1206 currently focused window (or dialog), we should not have
1207 any focused widgets in the focused window so we make sure
1208 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001209 if(windows != NULL &&
1210 window != windows &&
1211 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001212 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001213 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001214 redraw |= REDRAW_WIDGETS;*/
1215 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001216 }
1217
1218 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001219 /* If the mouse was clicked outside of the current window,
1220 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001221 if(dialog == NULL &&
1222 window != &desktop_window &&
1223 window != windows &&
1224 mouse_clicked) {
1225 /* Bring window to front. */
1226 ctk_window_open(window);
1227 redraw |= REDRAW_ALL;
1228 } else {
1229
adamdunkels965e2922003-06-30 20:44:57 +00001230 /* Find out which widget currently is under the mouse
1231 pointer and give it focus, unless it already has
1232 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001233 mxc = mxc - window->x - 1;
1234 myc = myc - window->y - 1;
1235
adamdunkels965e2922003-06-30 20:44:57 +00001236 /* See if the mouse pointer is on a widget. If so, it
1237 should be selected and, if the button is clicked,
1238 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001239 for(widget = window->active; widget != NULL;
1240 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001241
adamdunkelsb2486562003-04-11 20:22:03 +00001242 if(mxc >= widget->x &&
1243 mxc <= widget->x + widget->w &&
1244 (myc == widget->y ||
1245 ((widget->type == CTK_WIDGET_BITMAP ||
1246 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1247 widget->type == CTK_WIDGET_ICON) &&
1248 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001249 myc <= widget->y +
1250 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001251 break;
1252 }
1253 }
1254
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001255
1256 /* if the mouse is moved in the focused window, we emit
1257 a ctk_signal_pointer_move signal to the owner of the
1258 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001259 if(mouse_moved &&
1260 (window != &desktop_window ||
1261 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001262
adamdunkelsb2486562003-04-11 20:22:03 +00001263 dispatcher_emit(ctk_signal_pointer_move, NULL,
1264 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001265
1266 /* If there was a focused widget that is not below the
1267 mouse pointer, we remove focus from the widget and
1268 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001269 if(window->focused != NULL &&
1270 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001271 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001272 if(CTK_WIDGET_TYPE(window->focused) ==
1273 CTK_WIDGET_TEXTENTRY) {
1274 ((struct ctk_textentry *)(window->focused))->state =
1275 CTK_TEXTENTRY_NORMAL;
1276 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001277 window->focused = NULL;*/
1278 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001279 }
1280 redraw |= REDRAW_WIDGETS;
1281 if(widget != NULL) {
1282 select_widget(widget);
1283 }
1284 }
1285
1286 if(mouse_button_changed) {
1287 dispatcher_emit(ctk_signal_pointer_button,
1288 (ek_data_t)mouse_button,
1289 window->owner);
1290 if(mouse_clicked && widget != NULL) {
1291 select_widget(widget);
1292 redraw |= activate(widget);
1293 }
1294 }
1295 }
1296 }
1297 }
adamdunkelsc4902862003-04-09 00:30:45 +00001298 }
1299 }
adamdunkels19a787c2003-04-09 09:22:24 +00001300#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001301
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001302 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001303
1304 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001305
1306 screensaver_timer = 0;
1307
adamdunkelsb2486562003-04-11 20:22:03 +00001308 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001309
1310 if(dialog != NULL) {
1311 window = dialog;
1312 } else if(windows != NULL) {
1313 window = windows;
1314 } else {
1315 window = &desktop_window;
1316 }
1317 widget = window->focused;
1318
1319
1320 if(widget != NULL &&
1321 widget->type == CTK_WIDGET_TEXTENTRY &&
1322 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1323 textentry_input(c, (struct ctk_textentry *)widget);
1324 add_redrawwidget(widget);
1325#if CTK_CONF_MENUS
1326 } else if(menus.open != NULL) {
1327 redraw |= menus_input(c);
1328#endif /* CTK_CONF_MENUS */
1329 } else {
1330 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001331 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001332 switch_focus_widget(DOWN);
1333 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001334 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001335 switch_focus_widget(UP);
1336 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001337#if CTK_CONF_MENUS
1338 case CTK_CONF_MENU_KEY:
1339 if(dialog == NULL) {
1340 if(lastmenu == NULL) {
1341 menus.open = menus.menus;
1342 } else {
1343 menus.open = lastmenu;
1344 }
1345 menus.open->active = 0;
1346 redraw |= REDRAW_MENUS;
1347 }
1348 break;
1349#endif /* CTK_CONF_MENUS */
1350 case CTK_CONF_WINDOWSWITCH_KEY:
1351 if(windows != NULL) {
1352 for(window = windows; window->next != NULL;
1353 window = window->next);
1354 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001355 }
1356 break;
1357 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001358 if(c == CH_ENTER &&
1359 widget != NULL) {
1360 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001361 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001362 if(widget != NULL &&
1363 widget->type == CTK_WIDGET_TEXTENTRY) {
1364 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1365 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001366 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001367 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001368 /* window->focused = NULL;*/
1369 unfocus_widget(window->focused);
adamdunkels3af580f2003-08-11 22:27:13 +00001370 dispatcher_emit(ctk_signal_keypress, (void *)c,
1371 window->owner);
1372 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001373 }
1374 break;
1375 }
1376 }
1377
1378 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001379 widgetptr = redraw_widgets;
1380 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001381 ctk_widget_redraw(*widgetptr);
1382 *widgetptr = NULL;
1383 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001384 }
1385 redraw &= ~REDRAW_WIDGETS;
1386 redraw_widgetptr = 0;
1387 }
1388 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001389#if CTK_CONF_WINDOWMOVE
1390 } else if(mode == CTK_MODE_WINDOWMOVE) {
1391
1392 redraw = 0;
1393
1394 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001395
1396#if CTK_CONF_MOUSE_SUPPORT
1397
1398 /* If the mouse has moved, we move the window as well. */
1399 if(mouse_moved) {
1400
1401 if(window->w + mxc + 2 >= width) {
1402 window->x = width - 2 - window->w;
1403 } else {
1404 window->x = mxc;
1405 }
1406
1407 if(window->h + myc + 2 >= height) {
1408 window->y = height - 2 - window->h;
1409 } else {
1410 window->y = myc;
1411 }
1412 if(window->y > 0) {
1413 --window->y;
1414 }
1415
1416 redraw = REDRAW_ALL;
1417 }
1418
1419 /* Check if the mouse has been clicked, and stop moving the window
1420 if so. */
1421 if(mouse_button_changed &&
1422 mouse_button == 0) {
1423 mode = CTK_MODE_NORMAL;
1424 redraw = REDRAW_ALL;
1425 }
1426#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001427
1428 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1429
1430 screensaver_timer = 0;
1431
1432 c = ctk_arch_getkey();
1433
1434 switch(c) {
1435 case CH_CURS_RIGHT:
1436 ++window->x;
1437 if(window->x + window->w + 1 >= width) {
1438 --window->x;
1439 }
1440 redraw = REDRAW_ALL;
1441 break;
1442 case CH_CURS_LEFT:
1443 if(window->x > 0) {
1444 --window->x;
1445 }
1446 redraw = REDRAW_ALL;
1447 break;
1448 case CH_CURS_DOWN:
1449 ++window->y;
1450 if(window->y + window->h + 2 >= height) {
1451 --window->y;
1452 }
1453 redraw = REDRAW_ALL;
1454 break;
1455 case CH_CURS_UP:
1456 if(window->y > 0) {
1457 --window->y;
1458 }
1459 redraw = REDRAW_ALL;
1460 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001461 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001462 mode = CTK_MODE_NORMAL;
1463 redraw = REDRAW_ALL;
1464 break;
1465 }
1466 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001467#endif /* CTK_CONF_WINDOWMOVE */
1468 }
adamdunkelsb2486562003-04-11 20:22:03 +00001469
1470 if(redraw & REDRAW_ALL) {
1471 do_redraw_all(1, height);
1472#if CTK_CONF_MENUS
1473 } else if(redraw & REDRAW_MENUPART) {
1474 do_redraw_all(1, maxnitems + 1);
1475 } else if(redraw & REDRAW_MENUS) {
1476 ctk_draw_menus(&menus);
1477#endif /* CTK_CONF_MENUS */
1478 } else if(redraw & REDRAW_FOCUS) {
1479 if(dialog != NULL) {
1480 ctk_window_redraw(dialog);
1481 } else if(windows != NULL) {
1482 ctk_window_redraw(windows);
1483 } else {
1484 ctk_window_redraw(&desktop_window);
1485 }
1486 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001487 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001488 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1489 ctk_widget_redraw(*widgetptr);
1490 *widgetptr = NULL;
1491 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001492 }
1493 }
1494 redraw = 0;
1495 redraw_widgetptr = 0;
1496
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001497}
1498/*-----------------------------------------------------------------------------------*/