blob: ae47b52c7c3b006c113be43536d836c5ecc5335f [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 *
adamdunkels3af580f2003-08-11 22:27:13 +000035 * $Id: ctk.c,v 1.25 2003/08/11 22:27:13 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{
297 struct ctk_window *w2;
298
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;
adamdunkels3af580f2003-08-11 22:27:13 +0000396 redraw |= REDRAW_MENUPART;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000397 return;
398 }
399 }
400#endif /* CTK_CONF_MENUS */
401}
402/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000403static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000404do_redraw_all(unsigned char clipy1, unsigned char clipy2)
405{
406 struct ctk_window *w;
407 struct ctk_widget *widget;
408
409 if(mode != CTK_MODE_NORMAL &&
410 mode != CTK_MODE_WINDOWMOVE) {
411 return;
412 }
413
414 ctk_draw_clear(clipy1, clipy2);
415
416 /* Draw widgets in root window */
417 for(widget = desktop_window.active;
418 widget != NULL; widget = widget->next) {
adamdunkels66109622003-04-24 17:17:10 +0000419 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000420 }
421
422 /* Draw windows */
423 if(windows != NULL) {
424 /* Find the last window.*/
425 for(w = windows; w->next != NULL; w = w->next);
426
427 /* Draw the windows from back to front. */
428 for(; w != windows; w = w->prev) {
adamdunkels9d3a0e52003-04-02 09:53:59 +0000429 ctk_draw_clear_window(w, 0, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000430 ctk_draw_window(w, 0, clipy1, clipy2);
431 }
432 /* Draw focused window */
adamdunkels9d3a0e52003-04-02 09:53:59 +0000433 ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000434 ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
435 }
436
437 /* Draw dialog (if any) */
438 if(dialog != NULL) {
439 ctk_draw_dialog(dialog);
440 }
441
442#if CTK_CONF_MENUS
443 ctk_draw_menus(&menus);
444#endif /* CTK_CONF_MENUS */
445}
446/*-----------------------------------------------------------------------------------*/
447void
adamdunkels965e2922003-06-30 20:44:57 +0000448ctk_desktop_redraw(struct ctk_desktop *d)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000449{
450 if(DISPATCHER_CURRENT() == ctkid) {
451 if(mode == CTK_MODE_NORMAL ||
452 mode == CTK_MODE_WINDOWMOVE) {
453 do_redraw_all(1, height);
454 }
455 } else {
456 redraw |= REDRAW_ALL;
457 }
458}
459/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000460void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000461ctk_window_redraw(struct ctk_window *w)
462{
463 /* Only redraw the window if it is a dialog or if it is the foremost
464 window. */
465 if(mode != CTK_MODE_NORMAL) {
466 return;
467 }
468
469 if(w == dialog) {
470 ctk_draw_dialog(w);
471 } else if(dialog == NULL &&
472#if CTK_CONF_MENUS
473 menus.open == NULL &&
474#endif /* CTK_CONF_MENUS */
475 windows == w) {
476 ctk_draw_window(w, CTK_FOCUS_WINDOW,
477 0, height);
478 }
479}
480/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000481static void
adamdunkelsd07a5422003-04-05 12:22:35 +0000482window_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000483 unsigned char w, unsigned char h,
484 char *title)
485{
adamdunkels4b7a7ab2003-04-09 19:22:19 +0000486
487 if(w >= width - 2) {
488 window->x = 0;
489 } else {
490 window->x = (width - w - 2) / 2;
491 }
492 if(h >= height - 3) {
493 window->y = 0;
494 } else {
495 window->y = (height - h - 1) / 2;
496 }
497
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000498 window->w = w;
499 window->h = h;
500 window->title = title;
501 if(title != NULL) {
502 window->titlelen = strlen(title);
503 } else {
504 window->titlelen = 0;
505 }
506 window->next = window->prev = NULL;
507 window->owner = DISPATCHER_CURRENT();
508 window->active = window->inactive = window->focused = NULL;
509}
510/*-----------------------------------------------------------------------------------*/
511void
512ctk_window_new(struct ctk_window *window,
513 unsigned char w, unsigned char h,
514 char *title)
515{
516 window_new(window, w, h, title);
517
518 make_windowbuttons(window);
519}
520/*-----------------------------------------------------------------------------------*/
521void
adamdunkelsd07a5422003-04-05 12:22:35 +0000522ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *window,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000523 unsigned char w, unsigned char h)
524{
525 window_new(window, w, h, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000526}
adamdunkels3af580f2003-08-11 22:27:13 +0000527/*-----------------------------------------------------------------------------------*/
528void
adamdunkelsd07a5422003-04-05 12:22:35 +0000529ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000530 char *title)
531{
532#if CTK_CONF_MENUS
533 menu->next = NULL;
534 menu->title = title;
535 menu->titlelen = strlen(title);
536 menu->active = 0;
537 menu->nitems = 0;
538#endif /* CTK_CONF_MENUS */
539}
540/*-----------------------------------------------------------------------------------*/
541unsigned char
adamdunkelsd07a5422003-04-05 12:22:35 +0000542ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000543 char *name)
544{
545#if CTK_CONF_MENUS
546 if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
547 return 0;
548 }
549 menu->items[menu->nitems].title = name;
550 menu->items[menu->nitems].titlelen = strlen(name);
551 return menu->nitems++;
552#else
553 return 0;
554#endif /* CTK_CONF_MENUS */
555}
556/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000557static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000558add_redrawwidget(struct ctk_widget *w)
559{
560 static unsigned char i;
561
562 if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
563 redraw |= REDRAW_FOCUS;
564 } else {
565 redraw |= REDRAW_WIDGETS;
566 /* Check if it is in the queue already. If so, we don't add it
567 again. */
568 for(i = 0; i < redraw_widgetptr; ++i) {
569 if(redraw_widgets[i] == w) {
570 return;
571 }
572 }
573 redraw_widgets[redraw_widgetptr++] = w;
574 }
575}
576/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000577void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000578ctk_widget_redraw(struct ctk_widget *widget)
579{
580 struct ctk_window *window;
581
adamdunkels9f667f22003-04-16 18:29:19 +0000582 if(mode != CTK_MODE_NORMAL || widget == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000583 return;
584 }
585
586 /* If this function isn't called by CTK itself, we only queue the
587 redraw request. */
588 if(DISPATCHER_CURRENT() != ctkid) {
589 redraw |= REDRAW_WIDGETS;
590 add_redrawwidget(widget);
591 } else {
592
593 /* Only redraw widgets that are in the foremost window. If we
594 would allow redrawing widgets in non-focused windows, we would
595 have to redraw all the windows that cover the non-focused
596 window as well, which would lead to flickering.
597
598 Also, we avoid drawing any widgets when the menus are active.
599 */
600
601#if CTK_CONF_MENUS
602 if(menus.open == NULL)
603#endif /* CTK_CONF_MENUS */
604 {
605 window = widget->window;
606 if(window == dialog) {
607 ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
adamdunkels47efbc42003-08-07 00:03:26 +0000608 } else if(dialog == NULL &&
adamdunkels9795b2e2003-08-09 23:32:37 +0000609 (window == windows ||
610 window == &desktop_window)) {
adamdunkels66109622003-04-24 17:17:10 +0000611 ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000612 }
613 }
614 }
615}
616/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000617void CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000618ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
619 CC_REGISTER_ARG struct ctk_widget *widget)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000620{
621 if(widget->type == CTK_WIDGET_LABEL ||
622 widget->type == CTK_WIDGET_SEPARATOR) {
623 widget->next = window->inactive;
624 window->inactive = widget;
625 widget->window = window;
626 } else {
627 widget->next = window->active;
628 window->active = widget;
629 widget->window = window;
adamdunkels66109622003-04-24 17:17:10 +0000630 /* if(window->focused == NULL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000631 window->focused = widget;
adamdunkels66109622003-04-24 17:17:10 +0000632 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000633 }
634}
635/*-----------------------------------------------------------------------------------*/
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000636unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000637ctk_desktop_width(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000638{
639 return ctk_draw_width();
640}
641/*-----------------------------------------------------------------------------------*/
642unsigned char
adamdunkels965e2922003-06-30 20:44:57 +0000643ctk_desktop_height(struct ctk_desktop *w)
adamdunkelse2f4d2a2003-04-28 23:21:42 +0000644{
645 return ctk_draw_height();
646}
647/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000648static void CC_FASTCALL
adamdunkelsb2486562003-04-11 20:22:03 +0000649select_widget(struct ctk_widget *focus)
adamdunkelse0683312003-04-09 09:02:52 +0000650{
651 struct ctk_window *window;
652
653 window = focus->window;
654
655 if(focus != window->focused) {
656 window->focused = focus;
657 /* The operation changed the focus, so we emit a "hover" signal
658 for those widgets that support it. */
659
660 if(window->focused->type == CTK_WIDGET_HYPERLINK) {
661 dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
662 window->owner);
663 } else if(window->focused->type == CTK_WIDGET_BUTTON) {
664 dispatcher_emit(ctk_signal_button_hover, window->focused,
665 window->owner);
666 }
667
668 add_redrawwidget(window->focused);
adamdunkels58917a82003-04-18 00:18:38 +0000669
670 dispatcher_emit(ctk_signal_widget_select, focus,
671 focus->window->owner);
672
adamdunkelse0683312003-04-09 09:02:52 +0000673 }
674
675}
676/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000677#define UP 0
678#define DOWN 1
679#define LEFT 2
680#define RIGHT 3
adamdunkels3af580f2003-08-11 22:27:13 +0000681static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000682switch_focus_widget(unsigned char direction)
683{
684 register struct ctk_window *window;
685 register struct ctk_widget *focus;
686 struct ctk_widget *widget;
687
688
689 if(dialog != NULL) {
690 window = dialog;
691 } else {
692 window = windows;
693 }
694
695 /* If there are no windows open, we move focus around between the
696 icons on the root window instead. */
697 if(window == NULL) {
698 window = &desktop_window;
699 }
700
701 focus = window->focused;
adamdunkelse8bdfe12003-04-25 08:49:17 +0000702 if(focus == NULL) {
703 focus = window->active;
704 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000705 add_redrawwidget(focus);
706
707 if((direction & 1) == 0) {
708 /* Move focus "up" */
709 focus = focus->next;
710 } else {
711 /* Move focus "down" */
712 for(widget = window->active;
713 widget != NULL; widget = widget->next) {
714 if(widget->next == focus) {
715 break;
716 }
717 }
718 focus = widget;
719 if(focus == NULL) {
720 if(window->active != NULL) {
721 for(focus = window->active;
722 focus->next != NULL; focus = focus->next);
723 }
724 }
725 }
726 if(focus == NULL) {
727 focus = window->active;
728 }
adamdunkelse0683312003-04-09 09:02:52 +0000729
adamdunkelsb2486562003-04-11 20:22:03 +0000730 select_widget(focus);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000731}
732/*-----------------------------------------------------------------------------------*/
733#if CTK_CONF_MENUS
734static void
735switch_open_menu(unsigned char rightleft)
736{
737 struct ctk_menu *menu;
738
739 if(rightleft == 0) {
740 /* Move right */
741 for(menu = menus.menus; menu != NULL; menu = menu->next) {
742 if(menu->next == menus.open) {
743 break;
744 }
745 }
746 lastmenu = menus.open;
747 menus.open = menu;
748 if(menus.open == NULL) {
749 for(menu = menus.menus;
750 menu->next != NULL; menu = menu->next);
751 menus.open = menu;
752 }
753 } else {
754 /* Move to left */
755 lastmenu = menus.open;
756 menus.open = menus.open->next;
757 if(menus.open == NULL) {
758 menus.open = menus.menus;
759 }
760 }
761
adamdunkels66109622003-04-24 17:17:10 +0000762 menus.open->active = 0;
763
764 /* if(menus.open->nitems > maxnitems) {
765 maxnitems = menus.open->nitems;
766 }*/
767
adamdunkels965e2922003-06-30 20:44:57 +0000768 /* ctk_desktop_redraw();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000769}
770/*-----------------------------------------------------------------------------------*/
adamdunkels9795b2e2003-08-09 23:32:37 +0000771static void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772switch_menu_item(unsigned char updown)
773{
774 register struct ctk_menu *m;
775
776 m = menus.open;
777
778 if(updown == 0) {
779 /* Move up */
780 if(m->active == 0) {
781 m->active = m->nitems - 1;
782 } else {
783 --m->active;
784 if(m->items[m->active].title[0] == '-') {
785 --m->active;
786 }
787 }
788 } else {
789 /* Move down */
790 if(m->active >= m->nitems - 1) {
791 m->active = 0;
792 } else {
793 ++m->active;
794 if(m->items[m->active].title[0] == '-') {
795 ++m->active;
796 }
797 }
798 }
799
800}
801#endif /* CTK_CONF_MENUS */
802/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000803static unsigned char CC_FASTCALL
adamdunkelsd07a5422003-04-05 12:22:35 +0000804activate(CC_REGISTER_ARG struct ctk_widget *w)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000805{
806 static unsigned char len;
807
808 if(w->type == CTK_WIDGET_BUTTON) {
809 if(w == (struct ctk_widget *)&windows->closebutton) {
810#if CTK_CONF_WINDOWCLOSE
adamdunkels5cb690c2003-04-02 11:36:21 +0000811 dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000812 ctk_window_close(windows);
813 return REDRAW_ALL;
814#endif /* CTK_CONF_WINDOWCLOSE */
815 } else if(w == (struct ctk_widget *)&windows->titlebutton) {
816#if CTK_CONF_WINDOWCLOSE
817 mode = CTK_MODE_WINDOWMOVE;
818#endif /* CTK_CONF_WINDOWCLOSE */
819 } else {
adamdunkels58917a82003-04-18 00:18:38 +0000820 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000821 w->window->owner);
822 }
823#if CTK_CONF_ICONS
824 } else if(w->type == CTK_WIDGET_ICON) {
adamdunkels58917a82003-04-18 00:18:38 +0000825 dispatcher_emit(ctk_signal_widget_activate, w,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826 w->widget.icon.owner);
827#endif /* CTK_CONF_ICONS */
828 } else if(w->type == CTK_WIDGET_HYPERLINK) {
829 dispatcher_emit(ctk_signal_hyperlink_activate, w,
830 DISPATCHER_BROADCAST);
831 } else if(w->type == CTK_WIDGET_TEXTENTRY) {
832 if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
833 w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
834 len = strlen(w->widget.textentry.text);
835 if(w->widget.textentry.xpos > len) {
836 w->widget.textentry.xpos = len;
837 }
838 } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
839 w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
840 }
841 add_redrawwidget(w);
842 return REDRAW_WIDGETS;
adamdunkels58917a82003-04-18 00:18:38 +0000843 } else {
844 dispatcher_emit(ctk_signal_widget_activate, w,
845 w->window->owner);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000846 }
847 return REDRAW_NONE;
848}
849/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000850static void CC_FASTCALL
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851textentry_input(ctk_arch_key_t c,
adamdunkelsd07a5422003-04-05 12:22:35 +0000852 CC_REGISTER_ARG struct ctk_textentry *t)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000853{
adamdunkelsaf610eb2003-08-05 13:50:51 +0000854 register char *cptr, *cptr2;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000855 static unsigned char len, txpos, typos, tlen;
856
857 txpos = t->xpos;
858 typos = t->ypos;
859 tlen = t->len;
860
861 cptr = &t->text[txpos + typos * tlen];
862
863 switch(c) {
864 case CH_CURS_LEFT:
865 if(txpos > 0) {
866 --txpos;
867 }
868 break;
869
870 case CH_CURS_RIGHT:
871 if(txpos < tlen &&
872 *cptr != 0) {
873 ++txpos;
874 }
875 break;
876
877 case CH_CURS_UP:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000878 txpos = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000879 break;
880
881 case CH_CURS_DOWN:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882 txpos = strlen(t->text);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883 break;
884
885 case CH_ENTER:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000886 t->state = CTK_TEXTENTRY_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000887 break;
888
adamdunkels9795b2e2003-08-09 23:32:37 +0000889 case CTK_CONF_WIDGETDOWN_KEY:
890 t->state = CTK_TEXTENTRY_NORMAL;
891 switch_focus_widget(DOWN);
892 break;
893 case CTK_CONF_WIDGETUP_KEY:
894 t->state = CTK_TEXTENTRY_NORMAL;
895 switch_focus_widget(UP);
896 break;
897
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000898 default:
899 len = tlen - txpos - 1;
900 if(c == CH_DEL) {
901 if(txpos > 0 && len > 0) {
902 strncpy(cptr - 1, cptr,
903 len);
904 *(cptr + len - 1) = 0;
905 --txpos;
906 }
907 } else {
908 if(len > 0) {
909 cptr2 = cptr + len - 1;
910 while(cptr2 + 1 > cptr) {
911 *(cptr2 + 1) = *cptr2;
912 --cptr2;
913 }
914
915 *cptr = c;
916 ++txpos;
917 }
918 }
919 break;
920 }
921
922 t->xpos = txpos;
923 t->ypos = typos;
924}
925/*-----------------------------------------------------------------------------------*/
926#if CTK_CONF_MENUS
adamdunkels9795b2e2003-08-09 23:32:37 +0000927static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000928activate_menu(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000929{
930 struct ctk_window *w;
adamdunkelsb2486562003-04-11 20:22:03 +0000931
932 lastmenu = menus.open;
933 if(menus.open == &desktopmenu) {
934 for(w = windows; w != NULL; w = w->next) {
935 if(w->title == desktopmenu.items[desktopmenu.active].title) {
936 ctk_window_open(w);
937 menus.open = NULL;
938 return REDRAW_ALL;
939 }
940 }
941 } else {
942 dispatcher_emit(ctk_signal_menu_activate, menus.open,
943 DISPATCHER_BROADCAST);
944 }
945 menus.open = NULL;
946 return REDRAW_MENUPART;
947}
948/*-----------------------------------------------------------------------------------*/
adamdunkels3af580f2003-08-11 22:27:13 +0000949static unsigned char
adamdunkelsb2486562003-04-11 20:22:03 +0000950menus_input(ctk_arch_key_t c)
951{
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000952
953 if(menus.open->nitems > maxnitems) {
954 maxnitems = menus.open->nitems;
955 }
956
957
958 switch(c) {
959 case CH_CURS_RIGHT:
960 switch_open_menu(1);
961
962 return REDRAW_MENUPART;
963
964 case CH_CURS_DOWN:
965 switch_menu_item(1);
966 return REDRAW_MENUS;
967
968 case CH_CURS_LEFT:
969 switch_open_menu(0);
970 return REDRAW_MENUPART;
971
972 case CH_CURS_UP:
973 switch_menu_item(0);
974 return REDRAW_MENUS;
975
976 case CH_ENTER:
adamdunkelsb2486562003-04-11 20:22:03 +0000977 return activate_menu();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000978
adamdunkels88ed9c42003-03-28 12:10:09 +0000979 case CTK_CONF_MENU_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000980 lastmenu = menus.open;
981 menus.open = NULL;
982 return REDRAW_MENUPART;
983 }
adamdunkelsb2486562003-04-11 20:22:03 +0000984
985 return REDRAW_NONE;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986}
987#endif /* CTK_CONF_MENUS */
988/*-----------------------------------------------------------------------------------*/
989static void
adamdunkelscf90b0d2003-08-09 13:34:16 +0000990timer(void)
991{
992 if(mode == CTK_MODE_NORMAL) {
993 ++screensaver_timer;
adamdunkels9795b2e2003-08-09 23:32:37 +0000994 if(screensaver_timer >= ctk_screensaver_timeout) {
adamdunkelscf90b0d2003-08-09 13:34:16 +0000995#if CTK_CONF_SCREENSAVER
996 dispatcher_emit(ctk_signal_screensaver_start, NULL,
997 DISPATCHER_BROADCAST);
998#ifdef CTK_SCREENSAVER_INIT
999 CTK_SCREENSAVER_INIT();
1000#endif /* CTK_SCREENSAVER_INIT */
adamdunkels9795b2e2003-08-09 23:32:37 +00001001
adamdunkelscf90b0d2003-08-09 13:34:16 +00001002#endif /* CTK_CONF_SCREENSAVER */
1003 screensaver_timer = 0;
1004 }
1005 }
1006}
1007/*-----------------------------------------------------------------------------------*/
1008static void
adamdunkelsc4902862003-04-09 00:30:45 +00001009ctk_idle(void)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001010{
1011 static ctk_arch_key_t c;
adamdunkels19a787c2003-04-09 09:22:24 +00001012 static unsigned char i;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001013 register struct ctk_window *window;
adamdunkels19a787c2003-04-09 09:22:24 +00001014 register struct ctk_widget *widget;
adamdunkelscf90b0d2003-08-09 13:34:16 +00001015 register struct ctk_widget **widgetptr;
adamdunkels19a787c2003-04-09 09:22:24 +00001016#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001017 static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
1018 mouse_clicked;
1019 static unsigned char menux;
adamdunkelsaf610eb2003-08-05 13:50:51 +00001020 register struct ctk_menu *menu;
adamdunkelsb2486562003-04-11 20:22:03 +00001021
adamdunkels19a787c2003-04-09 09:22:24 +00001022#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelscf90b0d2003-08-09 13:34:16 +00001023
1024
1025 current = ek_clock();
adamdunkelsc4902862003-04-09 00:30:45 +00001026
adamdunkels9795b2e2003-08-09 23:32:37 +00001027 if((current - start) >= CLK_TCK) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001028 timer();
1029 start = current;
1030 }
1031
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001032#if CTK_CONF_MENUS
1033 if(menus.open != NULL) {
1034 maxnitems = menus.open->nitems;
1035 } else {
1036 maxnitems = 0;
1037 }
1038#endif /* CTK_CONF_MENUS */
adamdunkelsb2486562003-04-11 20:22:03 +00001039
1040#if CTK_CONF_MOUSE_SUPPORT
1041 mouse_button_changed = mouse_moved = mouse_clicked = 0;
1042
1043 /* See if there is any change in the buttons. */
1044 if(ctk_mouse_button() != mouse_button) {
1045 mouse_button = ctk_mouse_button();
1046 mouse_button_changed = 1;
1047 if(mouse_button == 0) {
1048 mouse_clicked = 1;
1049 }
1050 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001051
adamdunkelsb2486562003-04-11 20:22:03 +00001052 /* Check if the mouse pointer has moved. */
1053 if(ctk_mouse_x() != mouse_x ||
1054 ctk_mouse_y() != mouse_y) {
1055 mouse_x = ctk_mouse_x();
1056 mouse_y = ctk_mouse_y();
1057 mouse_moved = 1;
1058 }
1059
1060 mxc = ctk_mouse_xtoc(mouse_x);
1061 myc = ctk_mouse_ytoc(mouse_y);
1062#endif /* CTK_CONF_MOUSE_SUPPORT */
1063
1064
adamdunkels66109622003-04-24 17:17:10 +00001065#if CTK_CONF_SCREENSAVER
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001066 if(mode == CTK_MODE_SCREENSAVER) {
adamdunkelsb2486562003-04-11 20:22:03 +00001067 if(ctk_arch_keyavail()
1068#if CTK_CONF_MOUSE_SUPPORT
1069 || mouse_moved || mouse_button_changed
1070#endif /* CTK_CONF_MOUSE_SUPPORT */
1071 ) {
adamdunkels591724c2003-08-01 00:07:19 +00001072 dispatcher_emit(ctk_signal_screensaver_stop, NULL,
1073 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001074 mode = CTK_MODE_NORMAL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001075 }
adamdunkels66109622003-04-24 17:17:10 +00001076 } else
1077#endif /* CTK_CONF_SCREENSAVER */
1078 if(mode == CTK_MODE_NORMAL) {
adamdunkels19a787c2003-04-09 09:22:24 +00001079#if CTK_CONF_MOUSE_SUPPORT
adamdunkelsb2486562003-04-11 20:22:03 +00001080 /* If there is any change in the mouse conditions, find out in
1081 which window the mouse pointer currently is in order to send
1082 the correct signals, or bring a window to focus. */
1083 if(mouse_moved || mouse_button_changed) {
1084 ctk_mouse_show();
1085 screensaver_timer = 0;
1086
1087 if(myc == 0) {
1088 /* Here we should do whatever needs to be done when the mouse
1089 moves around and clicks in the menubar. */
1090 if(mouse_clicked) {
1091 /* Find out which menu that the mouse pointer is in. Start
1092 with the ->next menu after the desktop menu. We assume
1093 that the menus start one character from the left screen
1094 side and that the desktop menu is farthest to the
1095 right. */
1096 menux = 1;
1097 for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
1098 if(mxc >= menux && mxc <= menux + menu->titlelen) {
1099 break;
adamdunkelse0683312003-04-09 09:02:52 +00001100 }
adamdunkelsb2486562003-04-11 20:22:03 +00001101 menux += menu->titlelen;
adamdunkelsc4902862003-04-09 00:30:45 +00001102 }
adamdunkelsb2486562003-04-11 20:22:03 +00001103
1104 /* Also check desktop menu. */
1105 if(mxc >= width - 7 &&
1106 mxc <= width - 1) {
1107 menu = &desktopmenu;
1108 }
1109
1110 menus.open = menu;
1111 redraw |= REDRAW_MENUPART;
adamdunkelsc4902862003-04-09 00:30:45 +00001112 }
adamdunkelse0683312003-04-09 09:02:52 +00001113 } else {
adamdunkelsb2486562003-04-11 20:22:03 +00001114 --myc;
1115
1116 if(menus.open != NULL) {
1117 /* Do whatever needs to be done when a menu is open. */
1118
adamdunkelscf90b0d2003-08-09 13:34:16 +00001119 /* First check if the mouse pointer is in the currently open
1120 menu. */
adamdunkelsb2486562003-04-11 20:22:03 +00001121 if(menus.open == &desktopmenu) {
1122 menux = width - CTK_CONF_MENUWIDTH;
1123 } else {
1124 menux = 1;
1125 for(menu = menus.menus->next; menu != menus.open;
1126 menu = menu->next) {
1127 menux += menu->titlelen;
1128 }
1129 }
1130
adamdunkelscf90b0d2003-08-09 13:34:16 +00001131 /* Find out which of the menu items the mouse is pointing
1132 to. */
adamdunkelsb2486562003-04-11 20:22:03 +00001133 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
adamdunkels965e2922003-06-30 20:44:57 +00001134 if(myc <= menus.open->nitems) {
1135 menus.open->active = myc;
1136 } else {
1137 menus.open->active = menus.open->nitems - 1;
1138 }
adamdunkelsb2486562003-04-11 20:22:03 +00001139 }
1140
1141 if(mouse_clicked) {
adamdunkels965e2922003-06-30 20:44:57 +00001142 if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
1143 myc <= menus.open->nitems) {
adamdunkelsb2486562003-04-11 20:22:03 +00001144 redraw |= activate_menu();
1145 } else {
1146 lastmenu = menus.open;
1147 menus.open = NULL;
1148 redraw |= REDRAW_MENUPART;
1149 }
1150 } else {
1151 redraw |= REDRAW_MENUS;
1152 }
1153 } else {
1154
adamdunkels965e2922003-06-30 20:44:57 +00001155 /* Walk through the windows from top to bottom to see in
1156 which window the mouse pointer is. */
adamdunkelsb2486562003-04-11 20:22:03 +00001157 if(dialog != NULL) {
1158 window = dialog;
1159 } else {
1160 for(window = windows; window != NULL; window = window->next) {
1161 /* Check if the mouse is within the window. */
1162 if(mxc >= window->x &&
1163 mxc <= window->x + window->w &&
1164 myc >= window->y &&
1165 myc <= window->y + window->h) {
1166 break;
1167 }
1168 }
1169 }
1170
1171
1172 /* If we didn't find any window, and there are no windows
1173 open, the mouse pointer will definately be within the
1174 background desktop window. */
adamdunkels58917a82003-04-18 00:18:38 +00001175 if(window == NULL) {
adamdunkelsb2486562003-04-11 20:22:03 +00001176 window = &desktop_window;
1177 }
1178
adamdunkels965e2922003-06-30 20:44:57 +00001179 /* If the mouse pointer moves around outside of the
1180 currently focused window (or dialog), we should not have
1181 any focused widgets in the focused window so we make sure
1182 that there are none. */
adamdunkelsb2486562003-04-11 20:22:03 +00001183 if(windows != NULL &&
1184 window != windows &&
1185 windows->focused != NULL){
1186 add_redrawwidget(windows->focused);
1187 windows->focused = NULL;
1188 redraw |= REDRAW_WIDGETS;
1189 }
1190
1191 if(window != NULL) {
adamdunkels965e2922003-06-30 20:44:57 +00001192 /* If the mouse was clicked outside of the current window,
1193 we bring the clicked window to front. */
adamdunkelsb2486562003-04-11 20:22:03 +00001194 if(dialog == NULL &&
1195 window != &desktop_window &&
1196 window != windows &&
1197 mouse_clicked) {
1198 /* Bring window to front. */
1199 ctk_window_open(window);
1200 redraw |= REDRAW_ALL;
1201 } else {
1202
adamdunkels965e2922003-06-30 20:44:57 +00001203 /* Find out which widget currently is under the mouse
1204 pointer and give it focus, unless it already has
1205 focus. */
adamdunkelsb2486562003-04-11 20:22:03 +00001206 mxc = mxc - window->x - 1;
1207 myc = myc - window->y - 1;
1208
adamdunkels965e2922003-06-30 20:44:57 +00001209 /* See if the mouse pointer is on a widget. If so, it
1210 should be selected and, if the button is clicked,
1211 activated. */
adamdunkelsb2486562003-04-11 20:22:03 +00001212 for(widget = window->active; widget != NULL;
1213 widget = widget->next) {
1214 if(mxc >= widget->x &&
1215 mxc <= widget->x + widget->w &&
1216 (myc == widget->y ||
1217 ((widget->type == CTK_WIDGET_BITMAP ||
1218 /*widget->type == CTK_WIDGET_TEXTMAP ||*/
1219 widget->type == CTK_WIDGET_ICON) &&
1220 (myc >= widget->y &&
1221 myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
1222 break;
1223 }
1224 }
1225
1226
adamdunkels58917a82003-04-18 00:18:38 +00001227 if(mouse_moved &&
1228 (window != &desktop_window ||
1229 windows == NULL)) {
adamdunkelsb2486562003-04-11 20:22:03 +00001230 dispatcher_emit(ctk_signal_pointer_move, NULL,
1231 window->owner);
adamdunkels58917a82003-04-18 00:18:38 +00001232
adamdunkelsb2486562003-04-11 20:22:03 +00001233 if(window->focused != NULL &&
1234 widget != window->focused) {
1235 add_redrawwidget(window->focused);
1236 if(CTK_WIDGET_TYPE(window->focused) ==
1237 CTK_WIDGET_TEXTENTRY) {
1238 ((struct ctk_textentry *)(window->focused))->state =
1239 CTK_TEXTENTRY_NORMAL;
1240 }
1241 window->focused = NULL;
1242 }
1243 redraw |= REDRAW_WIDGETS;
1244 if(widget != NULL) {
1245 select_widget(widget);
1246 }
1247 }
1248
1249 if(mouse_button_changed) {
1250 dispatcher_emit(ctk_signal_pointer_button,
1251 (ek_data_t)mouse_button,
1252 window->owner);
1253 if(mouse_clicked && widget != NULL) {
1254 select_widget(widget);
1255 redraw |= activate(widget);
1256 }
1257 }
1258 }
1259 }
1260 }
adamdunkelsc4902862003-04-09 00:30:45 +00001261 }
1262 }
adamdunkels19a787c2003-04-09 09:22:24 +00001263#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsc4902862003-04-09 00:30:45 +00001264
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001265 while(ctk_arch_keyavail()) {
adamdunkelsb2486562003-04-11 20:22:03 +00001266
1267 ctk_mouse_hide();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001268
1269 screensaver_timer = 0;
1270
adamdunkelsb2486562003-04-11 20:22:03 +00001271 c = ctk_arch_getkey();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272
1273 if(dialog != NULL) {
1274 window = dialog;
1275 } else if(windows != NULL) {
1276 window = windows;
1277 } else {
1278 window = &desktop_window;
1279 }
1280 widget = window->focused;
1281
1282
1283 if(widget != NULL &&
1284 widget->type == CTK_WIDGET_TEXTENTRY &&
1285 widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
1286 textentry_input(c, (struct ctk_textentry *)widget);
1287 add_redrawwidget(widget);
1288#if CTK_CONF_MENUS
1289 } else if(menus.open != NULL) {
1290 redraw |= menus_input(c);
1291#endif /* CTK_CONF_MENUS */
1292 } else {
1293 switch(c) {
adamdunkels9795b2e2003-08-09 23:32:37 +00001294 case CTK_CONF_WIDGETDOWN_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001295 switch_focus_widget(DOWN);
1296 break;
adamdunkels9795b2e2003-08-09 23:32:37 +00001297 case CTK_CONF_WIDGETUP_KEY:
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001298 switch_focus_widget(UP);
1299 break;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001300#if CTK_CONF_MENUS
1301 case CTK_CONF_MENU_KEY:
1302 if(dialog == NULL) {
1303 if(lastmenu == NULL) {
1304 menus.open = menus.menus;
1305 } else {
1306 menus.open = lastmenu;
1307 }
1308 menus.open->active = 0;
1309 redraw |= REDRAW_MENUS;
1310 }
1311 break;
1312#endif /* CTK_CONF_MENUS */
1313 case CTK_CONF_WINDOWSWITCH_KEY:
1314 if(windows != NULL) {
1315 for(window = windows; window->next != NULL;
1316 window = window->next);
1317 ctk_window_open(window);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001318 }
1319 break;
1320 default:
adamdunkels3af580f2003-08-11 22:27:13 +00001321 if(c == CH_ENTER &&
1322 widget != NULL) {
1323 redraw |= activate(widget);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001324 } else {
adamdunkels3af580f2003-08-11 22:27:13 +00001325 add_redrawwidget(widget);
1326 if(widget != NULL &&
1327 widget->type == CTK_WIDGET_TEXTENTRY) {
1328 widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
1329 textentry_input(c, (struct ctk_textentry *)widget);
1330 } else {
1331 window->focused = NULL;
1332 dispatcher_emit(ctk_signal_keypress, (void *)c,
1333 window->owner);
1334 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001335 }
1336 break;
1337 }
1338 }
1339
1340 if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001341 widgetptr = redraw_widgets;
1342 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1343 /* if(redraw_widgets[i] != NULL) {
1344 ctk_widget_redraw(redraw_widgets[i]);
1345 }
1346 redraw_widgets[i] = NULL;*/
1347 ctk_widget_redraw(*widgetptr);
1348 *widgetptr = NULL;
1349 ++widgetptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001350 }
1351 redraw &= ~REDRAW_WIDGETS;
1352 redraw_widgetptr = 0;
1353 }
1354 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001355#if CTK_CONF_WINDOWMOVE
1356 } else if(mode == CTK_MODE_WINDOWMOVE) {
1357
1358 redraw = 0;
1359
1360 window = windows;
adamdunkelsb2486562003-04-11 20:22:03 +00001361
1362#if CTK_CONF_MOUSE_SUPPORT
1363
1364 /* If the mouse has moved, we move the window as well. */
1365 if(mouse_moved) {
1366
1367 if(window->w + mxc + 2 >= width) {
1368 window->x = width - 2 - window->w;
1369 } else {
1370 window->x = mxc;
1371 }
1372
1373 if(window->h + myc + 2 >= height) {
1374 window->y = height - 2 - window->h;
1375 } else {
1376 window->y = myc;
1377 }
1378 if(window->y > 0) {
1379 --window->y;
1380 }
1381
1382 redraw = REDRAW_ALL;
1383 }
1384
1385 /* Check if the mouse has been clicked, and stop moving the window
1386 if so. */
1387 if(mouse_button_changed &&
1388 mouse_button == 0) {
1389 mode = CTK_MODE_NORMAL;
1390 redraw = REDRAW_ALL;
1391 }
1392#endif /* CTK_CONF_MOUSE_SUPPORT */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001393
1394 while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
1395
1396 screensaver_timer = 0;
1397
1398 c = ctk_arch_getkey();
1399
1400 switch(c) {
1401 case CH_CURS_RIGHT:
1402 ++window->x;
1403 if(window->x + window->w + 1 >= width) {
1404 --window->x;
1405 }
1406 redraw = REDRAW_ALL;
1407 break;
1408 case CH_CURS_LEFT:
1409 if(window->x > 0) {
1410 --window->x;
1411 }
1412 redraw = REDRAW_ALL;
1413 break;
1414 case CH_CURS_DOWN:
1415 ++window->y;
1416 if(window->y + window->h + 2 >= height) {
1417 --window->y;
1418 }
1419 redraw = REDRAW_ALL;
1420 break;
1421 case CH_CURS_UP:
1422 if(window->y > 0) {
1423 --window->y;
1424 }
1425 redraw = REDRAW_ALL;
1426 break;
1427 case CH_ENTER:
1428 case CH_ESC:
1429 mode = CTK_MODE_NORMAL;
1430 redraw = REDRAW_ALL;
1431 break;
1432 }
1433 }
adamdunkelsb2486562003-04-11 20:22:03 +00001434 /* if(redraw & REDRAW_ALL) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001435 do_redraw_all(1, height);
1436 }
adamdunkelsb2486562003-04-11 20:22:03 +00001437 redraw = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001438#endif /* CTK_CONF_WINDOWMOVE */
1439 }
adamdunkelsb2486562003-04-11 20:22:03 +00001440
1441 if(redraw & REDRAW_ALL) {
1442 do_redraw_all(1, height);
1443#if CTK_CONF_MENUS
1444 } else if(redraw & REDRAW_MENUPART) {
1445 do_redraw_all(1, maxnitems + 1);
1446 } else if(redraw & REDRAW_MENUS) {
1447 ctk_draw_menus(&menus);
1448#endif /* CTK_CONF_MENUS */
1449 } else if(redraw & REDRAW_FOCUS) {
1450 if(dialog != NULL) {
1451 ctk_window_redraw(dialog);
1452 } else if(windows != NULL) {
1453 ctk_window_redraw(windows);
1454 } else {
1455 ctk_window_redraw(&desktop_window);
1456 }
1457 } else if(redraw & REDRAW_WIDGETS) {
adamdunkelscf90b0d2003-08-09 13:34:16 +00001458 widgetptr = redraw_widgets;
1459 /* for(i = 0; i < redraw_widgetptr; ++i) {
adamdunkelsb2486562003-04-11 20:22:03 +00001460 ctk_widget_redraw(redraw_widgets[i]);
adamdunkelscf90b0d2003-08-09 13:34:16 +00001461 }*/
1462 for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
1463 ctk_widget_redraw(*widgetptr);
1464 *widgetptr = NULL;
1465 ++widgetptr;
adamdunkelsb2486562003-04-11 20:22:03 +00001466 }
1467 }
1468 redraw = 0;
1469 redraw_widgetptr = 0;
1470
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001471}
1472/*-----------------------------------------------------------------------------------*/
adamdunkelscf90b0d2003-08-09 13:34:16 +00001473#if 0
adamdunkels78c03dc2003-04-09 13:45:05 +00001474static
1475DISPATCHER_SIGHANDLER(ctk_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001476{
adamdunkels78c03dc2003-04-09 13:45:05 +00001477 DISPATCHER_SIGHANDLER_ARGS(s, data);
1478
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001479 if(s == ctk_signal_timer) {
1480 if(mode == CTK_MODE_NORMAL) {
1481 ++screensaver_timer;
adamdunkelse2f4d2a2003-04-28 23:21:42 +00001482 if(screensaver_timer == ctk_screensaver_timeout) {
adamdunkels66109622003-04-24 17:17:10 +00001483#if CTK_CONF_SCREENSAVER
1484 dispatcher_emit(ctk_signal_screensaver_start, NULL,
1485 DISPATCHER_BROADCAST);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001486#ifdef CTK_SCREENSAVER_INIT
1487 CTK_SCREENSAVER_INIT();
1488#endif /* CTK_SCREENSAVER_INIT */
1489 mode = CTK_MODE_SCREENSAVER;
adamdunkels66109622003-04-24 17:17:10 +00001490#endif /* CTK_CONF_SCREENSAVER */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001491 screensaver_timer = 0;
1492 }
1493 }
1494 dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
1495 }
1496}
adamdunkelscf90b0d2003-08-09 13:34:16 +00001497#endif /* 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001498/*-----------------------------------------------------------------------------------*/
adamdunkelsd07a5422003-04-05 12:22:35 +00001499