blob: 5837591784ca658adcd12ac81dcb20201a8e7174 [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 *
adamdunkelsa05d5402003-08-24 22:38:12 +000035 * $Id: ctk.c,v 1.29 2003/08/24 22:38:12 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;
adamdunkelsa05d5402003-08-24 22:38:12 +0000725 focus->next != NULL; focus = focus->next);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000726 }
727 }
728 }
729 if(focus == NULL) {
730 focus = window->active;
731 }
adamdunkelse0683312003-04-09 09:02:52 +0000732
adamdunkelsb2486562003-04-11 20:22:03 +0000733 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000734}
735/*-----------------------------------------------------------------------------------*/
736#if CTK_CONF_MENUS
737static void
738switch_open_menu(unsigned char rightleft)
739{
740 struct ctk_menu *menu;
741
742 if(rightleft == 0) {
743 /* Move right */
744 for(menu = menus.menus; menu != NULL; menu = menu->next) {
745 if(menu->next == menus.open) {
746 break;
747 }
748 }
749 lastmenu = menus.open;
750 menus.open = menu;
751 if(menus.open == NULL) {
752 for(menu = menus.menus;
753 menu->next != NULL; menu = menu->next);
754 menus.open = menu;
755 }
756 } else {
757 /* Move to left */
758 lastmenu = menus.open;
759 menus.open = menus.open->next;
760 if(menus.open == NULL) {
761 menus.open = menus.menus;
762 }
763 }
764
adamdunkels66109622003-04-24 17:17:10 +0000765 menus.open->active = 0;
766
767 /* if(menus.open->nitems > maxnitems) {
768 maxnitems = menus.open->nitems;
769 }*/
770
adamdunkels965e2922003-06-30 20:44:57 +0000771 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772}
773/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000774static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000775switch_menu_item(unsigned char updown)
776{
777 register struct ctk_menu *m;
778
779 m = menus.open;
780
781 if(updown == 0) {
782 /* Move up */
783 if(m->active == 0) {
784 m->active = m->nitems - 1;
785 } else {
786 --m->active;
787 if(m->items[m->active].title[0] == '-') {
788 --m->active;
789 }
790 }
791 } else {
792 /* Move down */
793 if(m->active >= m->nitems - 1) {
794 m->active = 0;
795 } else {
796 ++m->active;
797 if(m->items[m->active].title[0] == '-') {
798 ++m->active;
799 }
800 }
801 }
802
803}
804#endif /* CTK_CONF_MENUS */
805/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000806static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000807activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808{
809 static unsigned char len;
810
811 if(w->type == CTK_WIDGET_BUTTON) {
812 if(w == (struct ctk_widget *)&windows->closebutton) {
813#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000814 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000815 ctk_window_close(windows);
816 return REDRAW_ALL;
817#endif /* CTK_CONF_WINDOWCLOSE */
818 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
819#if CTK_CONF_WINDOWCLOSE
820 mode = CTK_MODE_WINDOWMOVE;
821#endif /* CTK_CONF_WINDOWCLOSE */
822 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000823 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000824 w->window->owner);
825 }
826#if CTK_CONF_ICONS
827 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000828 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 w->widget.icon.owner);
830#endif /* CTK_CONF_ICONS */
831 } else if(w->type == CTK_WIDGET_HYPERLINK) {
832 dispatcher_emit(ctk_signal_hyperlink_activate, w,
833 DISPATCHER_BROADCAST);
834 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
835 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
836 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
837 len = strlen(w->widget.textentry.text);
838 if(w->widget.textentry.xpos > len) {
839 w->widget.textentry.xpos = len;
840 }
841 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
842 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
adamdunkels04ec5b42003-08-20 20:55:22 +0000843 dispatcher_emit(ctk_signal_widget_activate, w,
844 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 }
846 add_redrawwidget(w);
847 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000848 } else {
849 dispatcher_emit(ctk_signal_widget_activate, w,
850 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851 }
852 return REDRAW_NONE;
853}
854/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000855static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000857 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000859 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000860 static unsigned char len, txpos, typos, tlen;
861
862 txpos = t->xpos;
863 typos = t->ypos;
864 tlen = t->len;
865
866 cptr = &t->text[txpos + typos * tlen];
867
868 switch(c) {
869 case CH_CURS_LEFT:
870 if(txpos > 0) {
871 --txpos;
872 }
873 break;
874
875 case CH_CURS_RIGHT:
876 if(txpos < tlen &&
877 *cptr != 0) {
878 ++txpos;
879 }
880 break;
881
882 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000884 break;
885
886 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000887 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000888 break;
889
890 case CH_ENTER:
adamdunkels04ec5b42003-08-20 20:55:22 +0000891 /* t->state = CTK_TEXTENTRY_NORMAL;*/
892 activate((struct ctk_widget *)t);
adamdunkelsa05d5402003-08-24 22:38:12 +0000893 switch_focus_widget(DOWN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000894 break;
895
adamdunkels9795b2e2003-08-09 23:32:37 +0000896 case CTK_CONF_WIDGETDOWN_KEY:
897 t->state = CTK_TEXTENTRY_NORMAL;
898 switch_focus_widget(DOWN);
899 break;
900 case CTK_CONF_WIDGETUP_KEY:
901 t->state = CTK_TEXTENTRY_NORMAL;
902 switch_focus_widget(UP);
903 break;
904
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000905 default:
906 len = tlen - txpos - 1;
907 if(c == CH_DEL) {
908 if(txpos > 0 && len > 0) {
adamdunkels04ec5b42003-08-20 20:55:22 +0000909 strncpy(cptr - 1, cptr, len);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000910 *(cptr + len - 1) = 0;
911 --txpos;
912 }
913 } else {
914 if(len > 0) {
915 cptr2 = cptr + len - 1;
916 while(cptr2 + 1 > cptr) {
917 *(cptr2 + 1) = *cptr2;
918 --cptr2;
919 }
920
921 *cptr = c;
922 ++txpos;
923 }
924 }
925 break;
926 }
927
928 t->xpos = txpos;
929 t->ypos = typos;
930}
931/*-----------------------------------------------------------------------------------*/
932#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000933static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000934activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000935{
936 struct ctk_window *w;
adamdunkels4dd8eeb2003-08-15 18:49:22 +0000937
adamdunkelsb2486562003-04-11 20:22:03 +0000938 lastmenu = menus.open;
939 if(menus.open == &desktopmenu) {
940 for(w = windows; w != NULL; w = w->next) {
941 if(w->title == desktopmenu.items[desktopmenu.active].title) {
942 ctk_window_open(w);
943 menus.open = NULL;
944 return REDRAW_ALL;
945 }
946 }
947 } else {
948 dispatcher_emit(ctk_signal_menu_activate, menus.open,
949 DISPATCHER_BROADCAST);
950 }
951 menus.open = NULL;
952 return REDRAW_MENUPART;
953}
954/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000955static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000956menus_input(ctk_arch_key_t c)
957{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958
959 if(menus.open->nitems > maxnitems) {
960 maxnitems = menus.open->nitems;
961 }
962
963
964 switch(c) {
965 case CH_CURS_RIGHT:
966 switch_open_menu(1);
967
968 return REDRAW_MENUPART;
969
970 case CH_CURS_DOWN:
971 switch_menu_item(1);
972 return REDRAW_MENUS;
973
974 case CH_CURS_LEFT:
975 switch_open_menu(0);
976 return REDRAW_MENUPART;
977
978 case CH_CURS_UP:
979 switch_menu_item(0);
980 return REDRAW_MENUS;
981
982 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000983 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000984
adamdunkels88ed9c42003-03-28 12:10:09 +0000985 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986 lastmenu = menus.open;
987 menus.open = NULL;
988 return REDRAW_MENUPART;
989 }
adamdunkelsb2486562003-04-11 20:22:03 +0000990
991 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000992}
993#endif /* CTK_CONF_MENUS */
994/*-----------------------------------------------------------------------------------*/
995static void
adamdunkelscf90b0d2003-08-09 13:34:16 +0000996timer(void)
997{
998 if(mode == CTK_MODE_NORMAL) {
999 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +00001000 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001001#if CTK_CONF_SCREENSAVER
1002 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1003 DISPATCHER_BROADCAST);
1004#ifdef CTK_SCREENSAVER_INIT
1005 CTK_SCREENSAVER_INIT();
1006#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001007
adamdunkelscf90b0d2003-08-09 13:34:16 +00001008#endif /* CTK_CONF_SCREENSAVER */
1009 screensaver_timer = 0;
1010 }
1011 }
1012}
1013/*-----------------------------------------------------------------------------------*/
1014static void
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001015unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
1016{
1017 if(w != NULL) {
1018 redraw |= REDRAW_WIDGETS;
1019 add_redrawwidget(w);
1020 if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
1021 ((struct ctk_textentry *)w)->state =
1022 CTK_TEXTENTRY_NORMAL;
1023 }
1024 w->window->focused = NULL;
1025 }
1026}
1027/*-----------------------------------------------------------------------------------*/
1028static void
adamdunkelsc4902862003-04-09 00:30:45 +00001029ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001030{
1031 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001032 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001033 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001034 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001035 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001036#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001037 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1038 mouse_clicked;
1039 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001040 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001041
adamdunkels19a787c2003-04-09 09:22:24 +00001042#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001043
1044
1045 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001046
adamdunkels9795b2e2003-08-09 23:32:37 +00001047 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001048 timer();
1049 start = current;
1050 }
1051
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001052#if CTK_CONF_MENUS
1053 if(menus.open != NULL) {
1054 maxnitems = menus.open->nitems;
1055 } else {
1056 maxnitems = 0;
1057 }
1058#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001059
1060#if CTK_CONF_MOUSE_SUPPORT
1061 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1062
1063 /* See if there is any change in the buttons. */
1064 if(ctk_mouse_button() != mouse_button) {
1065 mouse_button = ctk_mouse_button();
1066 mouse_button_changed = 1;
1067 if(mouse_button == 0) {
1068 mouse_clicked = 1;
1069 }
1070 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001071
adamdunkelsb2486562003-04-11 20:22:03 +00001072 /* Check if the mouse pointer has moved. */
1073 if(ctk_mouse_x() != mouse_x ||
1074 ctk_mouse_y() != mouse_y) {
1075 mouse_x = ctk_mouse_x();
1076 mouse_y = ctk_mouse_y();
1077 mouse_moved = 1;
1078 }
1079
1080 mxc = ctk_mouse_xtoc(mouse_x);
1081 myc = ctk_mouse_ytoc(mouse_y);
1082#endif /* CTK_CONF_MOUSE_SUPPORT */
1083
1084
adamdunkels66109622003-04-24 17:17:10 +00001085#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001086 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001087 if(ctk_arch_keyavail()
1088#if CTK_CONF_MOUSE_SUPPORT
1089 || mouse_moved || mouse_button_changed
1090#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001091 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001092 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1093 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001094 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001095 }
adamdunkels66109622003-04-24 17:17:10 +00001096 } else
1097#endif /* CTK_CONF_SCREENSAVER */
1098 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001099#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001100 /* If there is any change in the mouse conditions, find out in
1101 which window the mouse pointer currently is in order to send
1102 the correct signals, or bring a window to focus. */
1103 if(mouse_moved || mouse_button_changed) {
1104 ctk_mouse_show();
1105 screensaver_timer = 0;
1106
1107 if(myc == 0) {
1108 /* Here we should do whatever needs to be done when the mouse
1109 moves around and clicks in the menubar. */
1110 if(mouse_clicked) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001111 static unsigned char titlelen;
1112
adamdunkelsb2486562003-04-11 20:22:03 +00001113 /* Find out which menu that the mouse pointer is in. Start
1114 with the ->next menu after the desktop menu. We assume
1115 that the menus start one character from the left screen
1116 side and that the desktop menu is farthest to the
1117 right. */
1118 menux = 1;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001119 for(menu = menus.menus->next;
1120 menu != NULL; menu = menu->next) {
1121 titlelen = menu->titlelen;
1122 if(mxc >= menux && mxc <= menux + titlelen) {
adamdunkelsb2486562003-04-11 20:22:03 +00001123 break;
adamdunkelse0683312003-04-09 09:02:52 +00001124 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001125 menux += titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001126 }
adamdunkelsb2486562003-04-11 20:22:03 +00001127
1128 /* Also check desktop menu. */
1129 if(mxc >= width - 7 &&
1130 mxc <= width - 1) {
1131 menu = &desktopmenu;
1132 }
1133
1134 menus.open = menu;
1135 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001136 }
adamdunkelse0683312003-04-09 09:02:52 +00001137 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001138 --myc;
1139
1140 if(menus.open != NULL) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001141 static unsigned char nitems;
1142
adamdunkelsb2486562003-04-11 20:22:03 +00001143 /* Do whatever needs to be done when a menu is open. */
1144
adamdunkelscf90b0d2003-08-09 13:34:16 +00001145 /* First check if the mouse pointer is in the currently open
1146 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001147 if(menus.open == &desktopmenu) {
1148 menux = width - CTK_CONF_MENUWIDTH;
1149 } else {
1150 menux = 1;
1151 for(menu = menus.menus->next; menu != menus.open;
1152 menu = menu->next) {
1153 menux += menu->titlelen;
1154 }
1155 }
1156
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001157 nitems = menus.open->nitems;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001158 /* Find out which of the menu items the mouse is pointing
1159 to. */
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001160 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
1161 if(myc <= nitems) {
adamdunkels965e2922003-06-30 20:44:57 +00001162 menus.open->active = myc;
1163 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001164 menus.open->active = nitems - 1;
adamdunkels965e2922003-06-30 20:44:57 +00001165 }
adamdunkelsb2486562003-04-11 20:22:03 +00001166 }
1167
1168 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001169 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001170 myc <= nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001171 redraw |= activate_menu();
1172 } else {
1173 lastmenu = menus.open;
1174 menus.open = NULL;
1175 redraw |= REDRAW_MENUPART;
1176 }
1177 } else {
1178 redraw |= REDRAW_MENUS;
1179 }
1180 } else {
1181
adamdunkels965e2922003-06-30 20:44:57 +00001182 /* Walk through the windows from top to bottom to see in
1183 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001184 if(dialog != NULL) {
1185 window = dialog;
1186 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001187 for(window = windows; window != NULL;
1188 window = window->next) {
1189
adamdunkelsb2486562003-04-11 20:22:03 +00001190 /* Check if the mouse is within the window. */
1191 if(mxc >= window->x &&
1192 mxc <= window->x + window->w &&
1193 myc >= window->y &&
1194 myc <= window->y + window->h) {
1195 break;
1196 }
1197 }
1198 }
1199
1200
1201 /* If we didn't find any window, and there are no windows
1202 open, the mouse pointer will definately be within the
1203 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001204 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001205 window = &desktop_window;
1206 }
1207
adamdunkels965e2922003-06-30 20:44:57 +00001208 /* If the mouse pointer moves around outside of the
1209 currently focused window (or dialog), we should not have
1210 any focused widgets in the focused window so we make sure
1211 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001212 if(windows != NULL &&
1213 window != windows &&
1214 windows->focused != NULL){
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001215 /*add_redrawwidget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001216 windows->focused = NULL;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001217 redraw |= REDRAW_WIDGETS;*/
1218 unfocus_widget(windows->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001219 }
1220
1221 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001222 /* If the mouse was clicked outside of the current window,
1223 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001224 if(dialog == NULL &&
1225 window != &desktop_window &&
1226 window != windows &&
1227 mouse_clicked) {
1228 /* Bring window to front. */
1229 ctk_window_open(window);
1230 redraw |= REDRAW_ALL;
1231 } else {
1232
adamdunkels965e2922003-06-30 20:44:57 +00001233 /* Find out which widget currently is under the mouse
1234 pointer and give it focus, unless it already has
1235 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001236 mxc = mxc - window->x - 1;
1237 myc = myc - window->y - 1;
1238
adamdunkels965e2922003-06-30 20:44:57 +00001239 /* See if the mouse pointer is on a widget. If so, it
1240 should be selected and, if the button is clicked,
1241 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001242 for(widget = window->active; widget != NULL;
1243 widget = widget->next) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001244
adamdunkelsb2486562003-04-11 20:22:03 +00001245 if(mxc >= widget->x &&
1246 mxc <= widget->x + widget->w &&
1247 (myc == widget->y ||
1248 ((widget->type == CTK_WIDGET_BITMAP ||
1249 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1250 widget->type == CTK_WIDGET_ICON) &&
1251 (myc >= widget->y &&
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001252 myc <= widget->y +
1253 ((struct ctk_bitmap *)widget)->h)))) {
adamdunkelsb2486562003-04-11 20:22:03 +00001254 break;
1255 }
1256 }
1257
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001258
1259 /* if the mouse is moved in the focused window, we emit
1260 a ctk_signal_pointer_move signal to the owner of the
1261 window. */
adamdunkels58917a82003-04-18 00:18:38 +00001262 if(mouse_moved &&
1263 (window != &desktop_window ||
1264 windows == NULL)) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001265
adamdunkelsb2486562003-04-11 20:22:03 +00001266 dispatcher_emit(ctk_signal_pointer_move, NULL,
1267 window->owner);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001268
1269 /* If there was a focused widget that is not below the
1270 mouse pointer, we remove focus from the widget and
1271 redraw it. */
adamdunkelsb2486562003-04-11 20:22:03 +00001272 if(window->focused != NULL &&
1273 widget != window->focused) {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001274 /* add_redrawwidget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001275 if(CTK_WIDGET_TYPE(window->focused) ==
1276 CTK_WIDGET_TEXTENTRY) {
1277 ((struct ctk_textentry *)(window->focused))->state =
1278 CTK_TEXTENTRY_NORMAL;
1279 }
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001280 window->focused = NULL;*/
1281 unfocus_widget(window->focused);
adamdunkelsb2486562003-04-11 20:22:03 +00001282 }
1283 redraw |= REDRAW_WIDGETS;
1284 if(widget != NULL) {
1285 select_widget(widget);
1286 }
1287 }
1288
1289 if(mouse_button_changed) {
1290 dispatcher_emit(ctk_signal_pointer_button,
1291 (ek_data_t)mouse_button,
1292 window->owner);
1293 if(mouse_clicked && widget != NULL) {
1294 select_widget(widget);
1295 redraw |= activate(widget);
1296 }
1297 }
1298 }
1299 }
1300 }
adamdunkelsc4902862003-04-09 00:30:45 +00001301 }
1302 }
adamdunkels19a787c2003-04-09 09:22:24 +00001303#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001304
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001305 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001306
1307 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001308
1309 screensaver_timer = 0;
1310
adamdunkelsb2486562003-04-11 20:22:03 +00001311 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001312
1313 if(dialog != NULL) {
1314 window = dialog;
1315 } else if(windows != NULL) {
1316 window = windows;
1317 } else {
1318 window = &desktop_window;
1319 }
1320 widget = window->focused;
1321
1322
1323 if(widget != NULL &&
1324 widget->type == CTK_WIDGET_TEXTENTRY &&
1325 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1326 textentry_input(c, (struct ctk_textentry *)widget);
1327 add_redrawwidget(widget);
1328#if CTK_CONF_MENUS
1329 } else if(menus.open != NULL) {
1330 redraw |= menus_input(c);
1331#endif /* CTK_CONF_MENUS */
1332 } else {
1333 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001334 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001335 switch_focus_widget(DOWN);
1336 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001337 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001338 switch_focus_widget(UP);
1339 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001340#if CTK_CONF_MENUS
1341 case CTK_CONF_MENU_KEY:
1342 if(dialog == NULL) {
1343 if(lastmenu == NULL) {
1344 menus.open = menus.menus;
1345 } else {
1346 menus.open = lastmenu;
1347 }
1348 menus.open->active = 0;
1349 redraw |= REDRAW_MENUS;
1350 }
1351 break;
1352#endif /* CTK_CONF_MENUS */
1353 case CTK_CONF_WINDOWSWITCH_KEY:
1354 if(windows != NULL) {
1355 for(window = windows; window->next != NULL;
1356 window = window->next);
1357 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001358 }
1359 break;
1360 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001361 if(c == CH_ENTER &&
1362 widget != NULL) {
1363 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001365 if(widget != NULL &&
1366 widget->type == CTK_WIDGET_TEXTENTRY) {
1367 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1368 textentry_input(c, (struct ctk_textentry *)widget);
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001369 add_redrawwidget(widget);
adamdunkels3af580f2003-08-11 22:27:13 +00001370 } else {
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001371 /* window->focused = NULL;*/
1372 unfocus_widget(window->focused);
adamdunkels3af580f2003-08-11 22:27:13 +00001373 dispatcher_emit(ctk_signal_keypress, (void *)c,
1374 window->owner);
1375 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001376 }
1377 break;
1378 }
1379 }
1380
1381 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001382 widgetptr = redraw_widgets;
1383 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001384 ctk_widget_redraw(*widgetptr);
1385 *widgetptr = NULL;
1386 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001387 }
1388 redraw &= ~REDRAW_WIDGETS;
1389 redraw_widgetptr = 0;
1390 }
1391 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001392#if CTK_CONF_WINDOWMOVE
1393 } else if(mode == CTK_MODE_WINDOWMOVE) {
1394
1395 redraw = 0;
1396
1397 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001398
1399#if CTK_CONF_MOUSE_SUPPORT
1400
1401 /* If the mouse has moved, we move the window as well. */
1402 if(mouse_moved) {
1403
1404 if(window->w + mxc + 2 >= width) {
1405 window->x = width - 2 - window->w;
1406 } else {
1407 window->x = mxc;
1408 }
1409
1410 if(window->h + myc + 2 >= height) {
1411 window->y = height - 2 - window->h;
1412 } else {
1413 window->y = myc;
1414 }
1415 if(window->y > 0) {
1416 --window->y;
1417 }
1418
1419 redraw = REDRAW_ALL;
1420 }
1421
1422 /* Check if the mouse has been clicked, and stop moving the window
1423 if so. */
1424 if(mouse_button_changed &&
1425 mouse_button == 0) {
1426 mode = CTK_MODE_NORMAL;
1427 redraw = REDRAW_ALL;
1428 }
1429#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001430
1431 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1432
1433 screensaver_timer = 0;
1434
1435 c = ctk_arch_getkey();
1436
1437 switch(c) {
1438 case CH_CURS_RIGHT:
1439 ++window->x;
1440 if(window->x + window->w + 1 >= width) {
1441 --window->x;
1442 }
1443 redraw = REDRAW_ALL;
1444 break;
1445 case CH_CURS_LEFT:
1446 if(window->x > 0) {
1447 --window->x;
1448 }
1449 redraw = REDRAW_ALL;
1450 break;
1451 case CH_CURS_DOWN:
1452 ++window->y;
1453 if(window->y + window->h + 2 >= height) {
1454 --window->y;
1455 }
1456 redraw = REDRAW_ALL;
1457 break;
1458 case CH_CURS_UP:
1459 if(window->y > 0) {
1460 --window->y;
1461 }
1462 redraw = REDRAW_ALL;
1463 break;
adamdunkels4dd8eeb2003-08-15 18:49:22 +00001464 default:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001465 mode = CTK_MODE_NORMAL;
1466 redraw = REDRAW_ALL;
1467 break;
1468 }
1469 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001470#endif /* CTK_CONF_WINDOWMOVE */
1471 }
adamdunkelsb2486562003-04-11 20:22:03 +00001472
1473 if(redraw & REDRAW_ALL) {
1474 do_redraw_all(1, height);
1475#if CTK_CONF_MENUS
1476 } else if(redraw & REDRAW_MENUPART) {
1477 do_redraw_all(1, maxnitems + 1);
1478 } else if(redraw & REDRAW_MENUS) {
1479 ctk_draw_menus(&menus);
1480#endif /* CTK_CONF_MENUS */
1481 } else if(redraw & REDRAW_FOCUS) {
1482 if(dialog != NULL) {
1483 ctk_window_redraw(dialog);
1484 } else if(windows != NULL) {
1485 ctk_window_redraw(windows);
1486 } else {
1487 ctk_window_redraw(&desktop_window);
1488 }
1489 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001490 widgetptr = redraw_widgets;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001491 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1492 ctk_widget_redraw(*widgetptr);
1493 *widgetptr = NULL;
1494 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001495 }
1496 }
1497 redraw = 0;
1498 redraw_widgetptr = 0;
1499
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001500}
1501/*-----------------------------------------------------------------------------------*/