blob: 4b33bd9f9bdf1232efd0b51366e702f1cc4f0858 [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 *
adamdunkelsc4dbb8d2003-08-29 20:38:54 +000035 * $Id: ctk.c,v 1.30 2003/08/29 20:38:54 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/*-----------------------------------------------------------------------------------*/
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000580static void
581widget_redraw(struct ctk_widget *widget)
582{
583 struct ctk_window *window;
584
585 if(mode != CTK_MODE_NORMAL || widget == NULL) {
586 return;
587 }
588
589 /* Only redraw widgets that are in the foremost window. If we would
590 allow redrawing widgets in non-focused windows, we would have to
591 redraw all the windows that cover the non-focused window as well,
592 which would lead to flickering.
593
594 Also, we avoid drawing any widgets when the menus are active.
595 */
596
597#if CTK_CONF_MENUS
598 if(menus.open == NULL)
599#endif /* CTK_CONF_MENUS */
600 {
601 window = widget->window;
602 if(window == dialog) {
603 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
604 } else if(dialog == NULL &&
605 (window == windows ||
606 window == &desktop_window)) {
607 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
608 }
609 }
610}
611/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000612void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000613ctk_widget_redraw(struct ctk_widget *widget)
614{
615 struct ctk_window *window;
616
adamdunkels9f667f22003-04-16 18:29:19 +0000617 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000618 return;
619 }
620
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000621 /* Since this function isn't called by CTK itself, we only queue the
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000622 redraw request. */
adamdunkelsc4dbb8d2003-08-29 20:38:54 +0000623 add_redrawwidget(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000624}
625/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000626void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000627ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
628 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000629{
630 if(widget->type == CTK_WIDGET_LABEL ||
631 widget->type == CTK_WIDGET_SEPARATOR) {
632 widget->next = window->inactive;
633 window->inactive = widget;
634 widget->window = window;
635 } else {
636 widget->next = window->active;
637 window->active = widget;
638 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000639 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000640 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000641 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000642 }
643}
644/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000645unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000646ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000647{
648 return ctk_draw_width();
649}
650/*-----------------------------------------------------------------------------------*/
651unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000652ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000653{
654 return ctk_draw_height();
655}
656/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000657static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000658select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000659{
660 struct ctk_window *window;
661
662 window = focus->window;
663
664 if(focus != window->focused) {
665 window->focused = focus;
666 /* The operation changed the focus, so we emit a "hover" signal
667 for those widgets that support it. */
668
669 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
670 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
671 window->owner);
672 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
673 dispatcher_emit(ctk_signal_button_hover, window->focused,
674 window->owner);
675 }
676
677 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000678
679 dispatcher_emit(ctk_signal_widget_select, focus,
680 focus->window->owner);
681
adamdunkelse0683312003-04-09 09:02:52 +0000682 }
683
684}
685/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000686#define UP 0
687#define DOWN 1
688#define LEFT 2
689#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000690static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000691switch_focus_widget(unsigned char direction)
692{
693 register struct ctk_window *window;
694 register struct ctk_widget *focus;
695 struct ctk_widget *widget;
696
697
698 if(dialog != NULL) {
699 window = dialog;
700 } else {
701 window = windows;
702 }
703
704 /* If there are no windows open, we move focus around between the
705 icons on the root window instead. */
706 if(window == NULL) {
707 window = &desktop_window;
708 }
709
710 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000711 if(focus == NULL) {
712 focus = window->active;
713 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000714 add_redrawwidget(focus);
715
716 if((direction & 1) == 0) {
717 /* Move focus "up" */
718 focus = focus->next;
719 } else {
720 /* Move focus "down" */
721 for(widget = window->active;
722 widget != NULL; widget = widget->next) {
723 if(widget->next == focus) {
724 break;
725 }
726 }
727 focus = widget;
728 if(focus == NULL) {
729 if(window->active != NULL) {
730 for(focus = window->active;
adamdunkelsa05d5402003-08-24 22:38:12 +0000731 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000732 }
733 }
734 }
735 if(focus == NULL) {
736 focus = window->active;
737 }
adamdunkelse0683312003-04-09 09:02:52 +0000738
adamdunkelsb2486562003-04-11 20:22:03 +0000739 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000740}
741/*-----------------------------------------------------------------------------------*/
742#if CTK_CONF_MENUS
743static void
744switch_open_menu(unsigned char rightleft)
745{
746 struct ctk_menu *menu;
747
748 if(rightleft == 0) {
749 /* Move right */
750 for(menu = menus.menus; menu != NULL; menu = menu->next) {
751 if(menu->next == menus.open) {
752 break;
753 }
754 }
755 lastmenu = menus.open;
756 menus.open = menu;
757 if(menus.open == NULL) {
758 for(menu = menus.menus;
759 menu->next != NULL; menu = menu->next);
760 menus.open = menu;
761 }
762 } else {
763 /* Move to left */
764 lastmenu = menus.open;
765 menus.open = menus.open->next;
766 if(menus.open == NULL) {
767 menus.open = menus.menus;
768 }
769 }
770
adamdunkels66109622003-04-24 17:17:10 +0000771 menus.open->active = 0;
772
773 /* if(menus.open->nitems > maxnitems) {
774 maxnitems = menus.open->nitems;
775 }*/
776
adamdunkels965e2922003-06-30 20:44:57 +0000777 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000778}
779/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000780static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781switch_menu_item(unsigned char updown)
782{
783 register struct ctk_menu *m;
784
785 m = menus.open;
786
787 if(updown == 0) {
788 /* Move up */
789 if(m->active == 0) {
790 m->active = m->nitems - 1;
791 } else {
792 --m->active;
793 if(m->items[m->active].title[0] == '-') {
794 --m->active;
795 }
796 }
797 } else {
798 /* Move down */
799 if(m->active >= m->nitems - 1) {
800 m->active = 0;
801 } else {
802 ++m->active;
803 if(m->items[m->active].title[0] == '-') {
804 ++m->active;
805 }
806 }
807 }
808
809}
810#endif /* CTK_CONF_MENUS */
811/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000812static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000813activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000814{
815 static unsigned char len;
816
817 if(w->type == CTK_WIDGET_BUTTON) {
818 if(w == (struct ctk_widget *)&windows->closebutton) {
819#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000820 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000821 ctk_window_close(windows);
822 return REDRAW_ALL;
823#endif /* CTK_CONF_WINDOWCLOSE */
824 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
825#if CTK_CONF_WINDOWCLOSE
826 mode = CTK_MODE_WINDOWMOVE;
827#endif /* CTK_CONF_WINDOWCLOSE */
828 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000829 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000830 w->window->owner);
831 }
832#if CTK_CONF_ICONS
833 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000834 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000835 w->widget.icon.owner);
836#endif /* CTK_CONF_ICONS */
837 } else if(w->type == CTK_WIDGET_HYPERLINK) {
838 dispatcher_emit(ctk_signal_hyperlink_activate, w,
839 DISPATCHER_BROADCAST);
840 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
841 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
842 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
843 len = strlen(w->widget.textentry.text);
844 if(w->widget.textentry.xpos > len) {
845 w->widget.textentry.xpos = len;
846 }
847 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
848 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +0000849 dispatcher_emit(ctk_signal_widget_activate, w,
850 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851 }
852 add_redrawwidget(w);
853 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000854 } else {
855 dispatcher_emit(ctk_signal_widget_activate, w,
856 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000857 }
858 return REDRAW_NONE;
859}
860/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000861static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000862textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000863 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000864{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000865 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000866 static unsigned char len, txpos, typos, tlen;
867
868 txpos = t->xpos;
869 typos = t->ypos;
870 tlen = t->len;
871
872 cptr = &t->text[txpos + typos * tlen];
873
874 switch(c) {
875 case CH_CURS_LEFT:
876 if(txpos > 0) {
877 --txpos;
878 }
879 break;
880
881 case CH_CURS_RIGHT:
882 if(txpos < tlen &&
883 *cptr != 0) {
884 ++txpos;
885 }
886 break;
887
888 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000889 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000890 break;
891
892 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000893 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000894 break;
895
896 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +0000897 /* t->state = CTK_TEXTENTRY_NORMAL;*/
898 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +0000899 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000900 break;
901
adamdunkels9795b2e2003-08-09 23:32:37 +0000902 case CTK_CONF_WIDGETDOWN_KEY:
903 t->state = CTK_TEXTENTRY_NORMAL;
904 switch_focus_widget(DOWN);
905 break;
906 case CTK_CONF_WIDGETUP_KEY:
907 t->state = CTK_TEXTENTRY_NORMAL;
908 switch_focus_widget(UP);
909 break;
910
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000911 default:
912 len = tlen - txpos - 1;
913 if(c == CH_DEL) {
914 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +0000915 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000916 *(cptr + len - 1) = 0;
917 --txpos;
918 }
919 } else {
920 if(len > 0) {
921 cptr2 = cptr + len - 1;
922 while(cptr2 + 1 > cptr) {
923 *(cptr2 + 1) = *cptr2;
924 --cptr2;
925 }
926
927 *cptr = c;
928 ++txpos;
929 }
930 }
931 break;
932 }
933
934 t->xpos = txpos;
935 t->ypos = typos;
936}
937/*-----------------------------------------------------------------------------------*/
938#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000939static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000940activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000941{
942 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000943
adamdunkelsb2486562003-04-11 20:22:03 +0000944 lastmenu = menus.open;
945 if(menus.open == &desktopmenu) {
946 for(w = windows; w != NULL; w = w->next) {
947 if(w->title == desktopmenu.items[desktopmenu.active].title) {
948 ctk_window_open(w);
949 menus.open = NULL;
950 return REDRAW_ALL;
951 }
952 }
953 } else {
954 dispatcher_emit(ctk_signal_menu_activate, menus.open,
955 DISPATCHER_BROADCAST);
956 }
957 menus.open = NULL;
958 return REDRAW_MENUPART;
959}
960/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000961static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000962menus_input(ctk_arch_key_t c)
963{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000964
965 if(menus.open->nitems > maxnitems) {
966 maxnitems = menus.open->nitems;
967 }
968
969
970 switch(c) {
971 case CH_CURS_RIGHT:
972 switch_open_menu(1);
973
974 return REDRAW_MENUPART;
975
976 case CH_CURS_DOWN:
977 switch_menu_item(1);
978 return REDRAW_MENUS;
979
980 case CH_CURS_LEFT:
981 switch_open_menu(0);
982 return REDRAW_MENUPART;
983
984 case CH_CURS_UP:
985 switch_menu_item(0);
986 return REDRAW_MENUS;
987
988 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000989 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000990
adamdunkels88ed9c42003-03-28 12:10:09 +0000991 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000992 lastmenu = menus.open;
993 menus.open = NULL;
994 return REDRAW_MENUPART;
995 }
adamdunkelsb2486562003-04-11 20:22:03 +0000996
997 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000998}
999#endif /* CTK_CONF_MENUS */
1000/*-----------------------------------------------------------------------------------*/
1001static void
adamdunkelscf90b0d2003-08-09 13:34:16 +00001002timer(void)
1003{
1004 if(mode == CTK_MODE_NORMAL) {
1005 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001006 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001007#if CTK_CONF_SCREENSAVER
1008 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1009 DISPATCHER_BROADCAST);
1010#ifdef CTK_SCREENSAVER_INIT
1011 CTK_SCREENSAVER_INIT();
1012#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001013
adamdunkelscf90b0d2003-08-09 13:34:16 +00001014#endif /* CTK_CONF_SCREENSAVER */
1015 screensaver_timer = 0;
1016 }
1017 }
1018}
1019/*-----------------------------------------------------------------------------------*/
1020static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001021unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1022{
1023 if(w != NULL) {
1024 redraw |= REDRAW_WIDGETS;
1025 add_redrawwidget(w);
1026 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1027 ((struct ctk_textentry *)w)->state =
1028 CTK_TEXTENTRY_NORMAL;
1029 }
1030 w->window->focused = NULL;
1031 }
1032}
1033/*-----------------------------------------------------------------------------------*/
1034static void
adamdunkelsc4902862003-04-09 00:30:45 +00001035ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001036{
1037 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001038 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001039 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001040 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001041 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001042#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001043 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1044 mouse_clicked;
1045 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001046 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001047
adamdunkels19a787c2003-04-09 09:22:24 +00001048#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001049
1050
1051 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001052
adamdunkels9795b2e2003-08-09 23:32:37 +00001053 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001054 timer();
1055 start = current;
1056 }
1057
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001058#if CTK_CONF_MENUS
1059 if(menus.open != NULL) {
1060 maxnitems = menus.open->nitems;
1061 } else {
1062 maxnitems = 0;
1063 }
1064#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001065
1066#if CTK_CONF_MOUSE_SUPPORT
1067 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1068
1069 /* See if there is any change in the buttons. */
1070 if(ctk_mouse_button() != mouse_button) {
1071 mouse_button = ctk_mouse_button();
1072 mouse_button_changed = 1;
1073 if(mouse_button == 0) {
1074 mouse_clicked = 1;
1075 }
1076 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077
adamdunkelsb2486562003-04-11 20:22:03 +00001078 /* Check if the mouse pointer has moved. */
1079 if(ctk_mouse_x() != mouse_x ||
1080 ctk_mouse_y() != mouse_y) {
1081 mouse_x = ctk_mouse_x();
1082 mouse_y = ctk_mouse_y();
1083 mouse_moved = 1;
1084 }
1085
1086 mxc = ctk_mouse_xtoc(mouse_x);
1087 myc = ctk_mouse_ytoc(mouse_y);
1088#endif /* CTK_CONF_MOUSE_SUPPORT */
1089
1090
adamdunkels66109622003-04-24 17:17:10 +00001091#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001092 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001093 if(ctk_arch_keyavail()
1094#if CTK_CONF_MOUSE_SUPPORT
1095 || mouse_moved || mouse_button_changed
1096#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001097 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001098 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1099 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001100 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001101 }
adamdunkels66109622003-04-24 17:17:10 +00001102 } else
1103#endif /* CTK_CONF_SCREENSAVER */
1104 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001105#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001106 /* If there is any change in the mouse conditions, find out in
1107 which window the mouse pointer currently is in order to send
1108 the correct signals, or bring a window to focus. */
1109 if(mouse_moved || mouse_button_changed) {
1110 ctk_mouse_show();
1111 screensaver_timer = 0;
1112
1113 if(myc == 0) {
1114 /* Here we should do whatever needs to be done when the mouse
1115 moves around and clicks in the menubar. */
1116 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001117 static unsigned char titlelen;
1118
adamdunkelsb2486562003-04-11 20:22:03 +00001119 /* Find out which menu that the mouse pointer is in. Start
1120 with the ->next menu after the desktop menu. We assume
1121 that the menus start one character from the left screen
1122 side and that the desktop menu is farthest to the
1123 right. */
1124 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001125 for(menu = menus.menus->next;
1126 menu != NULL; menu = menu->next) {
1127 titlelen = menu->titlelen;
1128 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001129 break;
adamdunkelse0683312003-04-09 09:02:52 +00001130 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001131 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001132 }
adamdunkelsb2486562003-04-11 20:22:03 +00001133
1134 /* Also check desktop menu. */
1135 if(mxc >= width - 7 &&
1136 mxc <= width - 1) {
1137 menu = &desktopmenu;
1138 }
1139
1140 menus.open = menu;
1141 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001142 }
adamdunkelse0683312003-04-09 09:02:52 +00001143 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001144 --myc;
1145
1146 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001147 static unsigned char nitems;
1148
adamdunkelsb2486562003-04-11 20:22:03 +00001149 /* Do whatever needs to be done when a menu is open. */
1150
adamdunkelscf90b0d2003-08-09 13:34:16 +00001151 /* First check if the mouse pointer is in the currently open
1152 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001153 if(menus.open == &desktopmenu) {
1154 menux = width - CTK_CONF_MENUWIDTH;
1155 } else {
1156 menux = 1;
1157 for(menu = menus.menus->next; menu != menus.open;
1158 menu = menu->next) {
1159 menux += menu->titlelen;
1160 }
1161 }
1162
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001163 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001164 /* Find out which of the menu items the mouse is pointing
1165 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001166 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1167 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001168 menus.open->active = myc;
1169 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001170 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001171 }
adamdunkelsb2486562003-04-11 20:22:03 +00001172 }
1173
1174 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001175 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001176 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001177 redraw |= activate_menu();
1178 } else {
1179 lastmenu = menus.open;
1180 menus.open = NULL;
1181 redraw |= REDRAW_MENUPART;
1182 }
1183 } else {
1184 redraw |= REDRAW_MENUS;
1185 }
1186 } else {
1187
adamdunkels965e2922003-06-30 20:44:57 +00001188 /* Walk through the windows from top to bottom to see in
1189 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001190 if(dialog != NULL) {
1191 window = dialog;
1192 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001193 for(window = windows; window != NULL;
1194 window = window->next) {
1195
adamdunkelsb2486562003-04-11 20:22:03 +00001196 /* Check if the mouse is within the window. */
1197 if(mxc >= window->x &&
1198 mxc <= window->x + window->w &&
1199 myc >= window->y &&
1200 myc <= window->y + window->h) {
1201 break;
1202 }
1203 }
1204 }
1205
1206
1207 /* If we didn't find any window, and there are no windows
1208 open, the mouse pointer will definately be within the
1209 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001210 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001211 window = &desktop_window;
1212 }
1213
adamdunkels965e2922003-06-30 20:44:57 +00001214 /* If the mouse pointer moves around outside of the
1215 currently focused window (or dialog), we should not have
1216 any focused widgets in the focused window so we make sure
1217 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001218 if(windows != NULL &&
1219 window != windows &&
1220 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001221 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001222 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001223 redraw |= REDRAW_WIDGETS;*/
1224 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001225 }
1226
1227 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001228 /* If the mouse was clicked outside of the current window,
1229 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001230 if(dialog == NULL &&
1231 window != &desktop_window &&
1232 window != windows &&
1233 mouse_clicked) {
1234 /* Bring window to front. */
1235 ctk_window_open(window);
1236 redraw |= REDRAW_ALL;
1237 } else {
1238
adamdunkels965e2922003-06-30 20:44:57 +00001239 /* Find out which widget currently is under the mouse
1240 pointer and give it focus, unless it already has
1241 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001242 mxc = mxc - window->x - 1;
1243 myc = myc - window->y - 1;
1244
adamdunkels965e2922003-06-30 20:44:57 +00001245 /* See if the mouse pointer is on a widget. If so, it
1246 should be selected and, if the button is clicked,
1247 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001248 for(widget = window->active; widget != NULL;
1249 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001250
adamdunkelsb2486562003-04-11 20:22:03 +00001251 if(mxc >= widget->x &&
1252 mxc <= widget->x + widget->w &&
1253 (myc == widget->y ||
1254 ((widget->type == CTK_WIDGET_BITMAP ||
1255 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1256 widget->type == CTK_WIDGET_ICON) &&
1257 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001258 myc <= widget->y +
1259 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001260 break;
1261 }
1262 }
1263
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001264
1265 /* if the mouse is moved in the focused window, we emit
1266 a ctk_signal_pointer_move signal to the owner of the
1267 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001268 if(mouse_moved &&
1269 (window != &desktop_window ||
1270 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001271
adamdunkelsb2486562003-04-11 20:22:03 +00001272 dispatcher_emit(ctk_signal_pointer_move, NULL,
1273 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001274
1275 /* If there was a focused widget that is not below the
1276 mouse pointer, we remove focus from the widget and
1277 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001278 if(window->focused != NULL &&
1279 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001280 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001281 if(CTK_WIDGET_TYPE(window->focused) ==
1282 CTK_WIDGET_TEXTENTRY) {
1283 ((struct ctk_textentry *)(window->focused))->state =
1284 CTK_TEXTENTRY_NORMAL;
1285 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001286 window->focused = NULL;*/
1287 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001288 }
1289 redraw |= REDRAW_WIDGETS;
1290 if(widget != NULL) {
1291 select_widget(widget);
1292 }
1293 }
1294
1295 if(mouse_button_changed) {
1296 dispatcher_emit(ctk_signal_pointer_button,
1297 (ek_data_t)mouse_button,
1298 window->owner);
1299 if(mouse_clicked && widget != NULL) {
1300 select_widget(widget);
1301 redraw |= activate(widget);
1302 }
1303 }
1304 }
1305 }
1306 }
adamdunkelsc4902862003-04-09 00:30:45 +00001307 }
1308 }
adamdunkels19a787c2003-04-09 09:22:24 +00001309#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001310
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001311 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001312
1313 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001314
1315 screensaver_timer = 0;
1316
adamdunkelsb2486562003-04-11 20:22:03 +00001317 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001318
1319 if(dialog != NULL) {
1320 window = dialog;
1321 } else if(windows != NULL) {
1322 window = windows;
1323 } else {
1324 window = &desktop_window;
1325 }
1326 widget = window->focused;
1327
1328
1329 if(widget != NULL &&
1330 widget->type == CTK_WIDGET_TEXTENTRY &&
1331 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1332 textentry_input(c, (struct ctk_textentry *)widget);
1333 add_redrawwidget(widget);
1334#if CTK_CONF_MENUS
1335 } else if(menus.open != NULL) {
1336 redraw |= menus_input(c);
1337#endif /* CTK_CONF_MENUS */
1338 } else {
1339 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001340 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001341 switch_focus_widget(DOWN);
1342 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001343 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001344 switch_focus_widget(UP);
1345 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001346#if CTK_CONF_MENUS
1347 case CTK_CONF_MENU_KEY:
1348 if(dialog == NULL) {
1349 if(lastmenu == NULL) {
1350 menus.open = menus.menus;
1351 } else {
1352 menus.open = lastmenu;
1353 }
1354 menus.open->active = 0;
1355 redraw |= REDRAW_MENUS;
1356 }
1357 break;
1358#endif /* CTK_CONF_MENUS */
1359 case CTK_CONF_WINDOWSWITCH_KEY:
1360 if(windows != NULL) {
1361 for(window = windows; window->next != NULL;
1362 window = window->next);
1363 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364 }
1365 break;
1366 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001367 if(c == CH_ENTER &&
1368 widget != NULL) {
1369 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001370 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001371 if(widget != NULL &&
1372 widget->type == CTK_WIDGET_TEXTENTRY) {
1373 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1374 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001375 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001376 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001377 /* window->focused = NULL;*/
1378 unfocus_widget(window->focused);
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001379 dispatcher_fastemit(ctk_signal_keypress, (void *)c,
1380 window->owner);
adamdunkels3af580f2003-08-11 22:27:13 +00001381 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001382 }
1383 break;
1384 }
1385 }
1386
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001387#if 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001388 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001389 widgetptr = redraw_widgets;
1390 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001391 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001392 *widgetptr = NULL;
1393 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001394 }
1395 redraw &= ~REDRAW_WIDGETS;
1396 redraw_widgetptr = 0;
1397 }
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001398#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001399 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001400#if CTK_CONF_WINDOWMOVE
1401 } else if(mode == CTK_MODE_WINDOWMOVE) {
1402
1403 redraw = 0;
1404
1405 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001406
1407#if CTK_CONF_MOUSE_SUPPORT
1408
1409 /* If the mouse has moved, we move the window as well. */
1410 if(mouse_moved) {
1411
1412 if(window->w + mxc + 2 >= width) {
1413 window->x = width - 2 - window->w;
1414 } else {
1415 window->x = mxc;
1416 }
1417
1418 if(window->h + myc + 2 >= height) {
1419 window->y = height - 2 - window->h;
1420 } else {
1421 window->y = myc;
1422 }
1423 if(window->y > 0) {
1424 --window->y;
1425 }
1426
1427 redraw = REDRAW_ALL;
1428 }
1429
1430 /* Check if the mouse has been clicked, and stop moving the window
1431 if so. */
1432 if(mouse_button_changed &&
1433 mouse_button == 0) {
1434 mode = CTK_MODE_NORMAL;
1435 redraw = REDRAW_ALL;
1436 }
1437#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001438
1439 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1440
1441 screensaver_timer = 0;
1442
1443 c = ctk_arch_getkey();
1444
1445 switch(c) {
1446 case CH_CURS_RIGHT:
1447 ++window->x;
1448 if(window->x + window->w + 1 >= width) {
1449 --window->x;
1450 }
1451 redraw = REDRAW_ALL;
1452 break;
1453 case CH_CURS_LEFT:
1454 if(window->x > 0) {
1455 --window->x;
1456 }
1457 redraw = REDRAW_ALL;
1458 break;
1459 case CH_CURS_DOWN:
1460 ++window->y;
1461 if(window->y + window->h + 2 >= height) {
1462 --window->y;
1463 }
1464 redraw = REDRAW_ALL;
1465 break;
1466 case CH_CURS_UP:
1467 if(window->y > 0) {
1468 --window->y;
1469 }
1470 redraw = REDRAW_ALL;
1471 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001472 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001473 mode = CTK_MODE_NORMAL;
1474 redraw = REDRAW_ALL;
1475 break;
1476 }
1477 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001478#endif /* CTK_CONF_WINDOWMOVE */
1479 }
adamdunkelsb2486562003-04-11 20:22:03 +00001480
1481 if(redraw & REDRAW_ALL) {
1482 do_redraw_all(1, height);
1483#if CTK_CONF_MENUS
1484 } else if(redraw & REDRAW_MENUPART) {
1485 do_redraw_all(1, maxnitems + 1);
1486 } else if(redraw & REDRAW_MENUS) {
1487 ctk_draw_menus(&menus);
1488#endif /* CTK_CONF_MENUS */
1489 } else if(redraw & REDRAW_FOCUS) {
1490 if(dialog != NULL) {
1491 ctk_window_redraw(dialog);
1492 } else if(windows != NULL) {
1493 ctk_window_redraw(windows);
1494 } else {
1495 ctk_window_redraw(&desktop_window);
1496 }
1497 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001498 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001499 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelsc4dbb8d2003-08-29 20:38:54 +00001500 widget_redraw(*widgetptr);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001501 *widgetptr = NULL;
1502 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001503 }
1504 }
1505 redraw = 0;
1506 redraw_widgetptr = 0;
1507
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001508}
1509/*-----------------------------------------------------------------------------------*/