Rewrote mouse pointer support and it now works with menus, icons, widgets, for switching focus between windows and for moving windows
diff --git a/contiki/ctk/ctk.c b/contiki/ctk/ctk.c
index 2dc40b7..68e9eab 100644
--- a/contiki/ctk/ctk.c
+++ b/contiki/ctk/ctk.c
@@ -32,7 +32,7 @@
  *
  * This file is part of the "ctk" console GUI toolkit for cc65
  *
- * $Id: ctk.c,v 1.11 2003/04/09 19:22:19 adamdunkels Exp $
+ * $Id: ctk.c,v 1.12 2003/04/11 20:22:03 adamdunkels Exp $
  *
  */
 
@@ -98,11 +98,10 @@
   ctk_signal_menu_activate,
   ctk_signal_window_close,
   ctk_signal_pointer_move,
-  ctk_signal_pointer_down,
-  ctk_signal_pointer_up;
+  ctk_signal_pointer_button;
 
 #if CTK_CONF_MOUSE_SUPPORT
-unsigned short mouse_last_x, mouse_last_y, mouse_last_button;
+unsigned short mouse_x, mouse_y, mouse_button;
 #endif /* CTK_CONF_MOUSE_SUPPORT */
 
 static unsigned short screensaver_timer;
@@ -151,16 +150,18 @@
   menus.menus = menus.desktopmenu = &desktopmenu;
 #endif /* CTK_CONF_MENUS */
 
+#if CTK_CONF_MOUSE_SUPPORT
   ctk_mouse_init();
+  ctk_mouse_show();
+#endif /* CTK_CONF_MOUSE_SUPPORT */
   
   ctk_draw_init();
 
   height = ctk_draw_height();
   width = ctk_draw_width();
-
+  
   desktop_window.active = NULL;
-
-
+  
   ctk_signal_keypress = dispatcher_sigalloc();
   ctk_signal_timer = dispatcher_sigalloc();
   ctk_signal_button_activate = dispatcher_sigalloc();
@@ -171,8 +172,7 @@
   ctk_signal_window_close = dispatcher_sigalloc();
 
   ctk_signal_pointer_move = dispatcher_sigalloc();
-  ctk_signal_pointer_down = dispatcher_sigalloc();
-  ctk_signal_pointer_up = dispatcher_sigalloc();
+  ctk_signal_pointer_button = dispatcher_sigalloc();
   
   dispatcher_listen(ctk_signal_timer);
   dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
@@ -605,7 +605,7 @@
 }
 /*-----------------------------------------------------------------------------------*/
 static void
-focus_widget(struct ctk_widget *focus)
+select_widget(struct ctk_widget *focus)
 {
   struct ctk_window *window;
 
@@ -679,7 +679,7 @@
     focus = window->active;
   }
 
-  focus_widget(focus);
+  select_widget(focus);
 }
 /*-----------------------------------------------------------------------------------*/
 #if CTK_CONF_MENUS
@@ -897,9 +897,30 @@
 /*-----------------------------------------------------------------------------------*/
 #if CTK_CONF_MENUS
 static unsigned char
-menus_input(ctk_arch_key_t c)
+activate_menu(void)
 {
   struct ctk_window *w;
+    
+  lastmenu = menus.open;
+  if(menus.open == &desktopmenu) {
+    for(w = windows; w != NULL; w = w->next) {
+      if(w->title == desktopmenu.items[desktopmenu.active].title) {
+	ctk_window_open(w);
+	menus.open = NULL;
+	return REDRAW_ALL;
+      }
+    }
+  } else {
+    dispatcher_emit(ctk_signal_menu_activate, menus.open,
+		    DISPATCHER_BROADCAST);
+  }
+  menus.open = NULL;
+  return REDRAW_MENUPART;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+menus_input(ctk_arch_key_t c)
+{
 
   if(menus.open->nitems > maxnitems) {
     maxnitems = menus.open->nitems;
@@ -925,27 +946,15 @@
     return REDRAW_MENUS;
     
   case CH_ENTER:
-    lastmenu = menus.open;
-    if(menus.open == &desktopmenu) {
-      for(w = windows; w != NULL; w = w->next) {
-	if(w->title == desktopmenu.items[desktopmenu.active].title) {
-	  ctk_window_open(w);
-	  menus.open = NULL;
-	  return REDRAW_ALL;
-	}
-      }
-    } else {
-      dispatcher_emit(ctk_signal_menu_activate, menus.open,
-		      DISPATCHER_BROADCAST);
-    }
-    menus.open = NULL;
-    return REDRAW_MENUPART;
+    return activate_menu();
 
   case CTK_CONF_MENU_KEY:
     lastmenu = menus.open;
     menus.open = NULL;
     return REDRAW_MENUPART;
   }
+
+  return REDRAW_NONE;
 }
 #endif /* CTK_CONF_MENUS */
 /*-----------------------------------------------------------------------------------*/
@@ -957,7 +966,11 @@
   register struct ctk_window *window;
   register struct ctk_widget *widget;
 #if CTK_CONF_MOUSE_SUPPORT 
-  static unsigned char mxc, myc, mouse_clicked;
+  static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
+    mouse_clicked;
+  static unsigned char menux;
+  struct ctk_menu *menu;
+
 #endif /* CTK_CONF_MOUSE_SUPPORT */
   
 #if CTK_CONF_MENUS
@@ -967,96 +980,229 @@
     maxnitems = 0;
   }
 #endif /* CTK_CONF_MENUS */
+
+#if CTK_CONF_MOUSE_SUPPORT
+  mouse_button_changed = mouse_moved = mouse_clicked = 0;
+
+  /* See if there is any change in the buttons. */
+  if(ctk_mouse_button() != mouse_button) {
+    mouse_button = ctk_mouse_button();
+    mouse_button_changed = 1;
+    if(mouse_button == 0) {
+      mouse_clicked = 1;
+    }
+  }
   
+  /* Check if the mouse pointer has moved. */
+  if(ctk_mouse_x() != mouse_x ||
+     ctk_mouse_y() != mouse_y) {
+    mouse_x = ctk_mouse_x();
+    mouse_y = ctk_mouse_y();
+    mouse_moved = 1;
+  }
+
+  mxc = ctk_mouse_xtoc(mouse_x);
+  myc = ctk_mouse_ytoc(mouse_y); 
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+
+
   if(mode == CTK_MODE_SCREENSAVER) {
 #ifdef CTK_SCREENSAVER_RUN
     CTK_SCREENSAVER_RUN();
 #endif /* CTK_SCREENSAVER_RUN */
-    if(ctk_arch_keyavail()) {
+    if(ctk_arch_keyavail()
+#if CTK_CONF_MOUSE_SUPPORT
+       || mouse_moved || mouse_button_changed
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+       ) {
       mode = CTK_MODE_NORMAL;
       ctk_draw_init();
       ctk_redraw();
     }
   } else if(mode == CTK_MODE_NORMAL) {
 #if CTK_CONF_MOUSE_SUPPORT 
-    if(dialog != NULL) {
-      window = dialog;
-    } else {
-      window = windows;
-    }
-
-    /* If there has been a change in the mouse button(s), we send out
-       a signal. */
-    mouse_clicked = 0;
-    if(ctk_mouse_button() != mouse_last_button) {
-      mouse_last_button = ctk_mouse_button();
-      if(mouse_last_button == 0) {
-	dispatcher_emit(ctk_signal_pointer_up, NULL, window->owner);
-      } else {
-	dispatcher_emit(ctk_signal_pointer_down, (ek_data_t)mouse_last_button,
-			window->owner);
-	mouse_clicked = 1;
-      }
-    }
-    
-    /* Check if the mouse pointer has moved, and if so we emit a
-       signal. */
-    if(ctk_mouse_x() != mouse_last_x ||
-       ctk_mouse_y() != mouse_last_y ||
-       mouse_clicked != 0) {            
-      mouse_last_x = ctk_mouse_x();
-      mouse_last_y = ctk_mouse_y();
-      dispatcher_emit(ctk_signal_pointer_move, NULL, window->owner);
-
-      /* Find out which widget currently is under the mouse pointer
-	 and give it focus, unless it already has focus. */
-      mxc = ctk_mouse_xtoc(mouse_last_x);
-      myc = ctk_mouse_ytoc(mouse_last_y) - 1;
- 	
-      /* Check if the mouse is in the current window. */
-      if(mxc >= window->x &&
-	 mxc <= window->x + window->w &&
-	 myc >= window->y &&
-	 myc <= window->y + window->h) {
-	
-	mxc = mxc - window->x - 1;
-	myc = myc - window->y - 1;
-	
-	
-	redraw |= REDRAW_WIDGETS;
-	add_redrawwidget(window->focused);
-	window->focused = NULL;
-	
-	/* Now find the appropriate widget to assign focus to. */
-	for(widget = window->active; widget != NULL; widget = widget->next) {
-	  if(mxc >= widget->x &&
-	     mxc <= widget->x + widget->w &&
-	     myc == widget->y /* &&
-	     ((widget->type == CTK_WIDGET_BITMAP ||
-	       widget->type == CTK_WIDGET_TEXTENTRY ||
-	       widget->type == CTK_WIDGET_ICON) &&
-	       (myc <= widget->y + ((struct ctk_bitmap *)widget)->h))*/) {
-	    focus_widget(widget);
-	    if(mouse_clicked != 0) {
-	      redraw |= activate(widget);
+    /* If there is any change in the mouse conditions, find out in
+       which window the mouse pointer currently is in order to send
+       the correct signals, or bring a window to focus. */
+    if(mouse_moved || mouse_button_changed) {
+      ctk_mouse_show();
+      screensaver_timer = 0;
+      
+      if(myc == 0) {
+	/* Here we should do whatever needs to be done when the mouse
+	   moves around and clicks in the menubar. */
+	if(mouse_clicked) {
+	  /* Find out which menu that the mouse pointer is in. Start
+	     with the ->next menu after the desktop menu. We assume
+	     that the menus start one character from the left screen
+	     side and that the desktop menu is farthest to the
+	     right. */
+	  menux = 1;
+	  for(menu = menus.menus->next; menu != NULL; menu = menu->next) {
+	    if(mxc >= menux && mxc <= menux + menu->titlelen) {
+	      break;
 	    }
-	    break;
+	    menux += menu->titlelen;
 	  }
+	  
+	  /* Also check desktop menu. */
+	  if(mxc >= width - 7 &&
+	     mxc <= width - 1) {
+	    menu = &desktopmenu;
+	  }
+	  
+	  menus.open = menu;
+	  redraw |= REDRAW_MENUPART;
 	}
       } else {
-	redraw |= REDRAW_WIDGETS;
-	add_redrawwidget(window->focused);
-	window->focused = NULL;
+	--myc;
+
+	if(menus.open != NULL) {
+	  /* Do whatever needs to be done when a menu is open. */
+
+	  if(menus.open == &desktopmenu) {
+	    menux = width - CTK_CONF_MENUWIDTH;
+	  } else {
+	    menux = 1;
+	    for(menu = menus.menus->next; menu != menus.open;
+		menu = menu->next) {
+	      menux += menu->titlelen;
+	    }
+	  }
+
+	  if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
+	    menus.open->active = myc;
+	  }
+	  
+	  if(mouse_clicked) {
+	    if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {
+	      redraw |= activate_menu();
+	    } else {
+	      lastmenu = menus.open;
+	      menus.open = NULL;
+	      redraw |= REDRAW_MENUPART;
+	    }
+	  } else {
+	    redraw |= REDRAW_MENUS;	  
+	  }
+	} else {
+
+	  /* Walk through the windows from top to bottom to see in which
+	     window the mouse pointer is. */
+	  if(dialog != NULL) {
+	    window = dialog;
+	  } else {	  	 	  
+	    for(window = windows; window != NULL; window = window->next) {
+	      /* Check if the mouse is within the window. */
+	      if(mxc >= window->x &&
+		 mxc <= window->x + window->w &&
+		 myc >= window->y &&
+		 myc <= window->y + window->h) {
+		break;       	
+	      }
+	    }
+	  }
+
+
+	  /* If we didn't find any window, and there are no windows
+	     open, the mouse pointer will definately be within the
+	     background desktop window. */
+	  if(window == NULL &&
+	     windows == NULL) {
+	    window = &desktop_window;
+	  }
+
+	  /* If the mouse pointer moves around outside of the currently
+	     focused window (or dialog), we should not have any focused
+	     widgets in the focused window so we make sure that there
+	     are none. */
+	  if(windows != NULL &&
+	     window != windows &&
+	     windows->focused != NULL){	  
+	    add_redrawwidget(windows->focused);
+	    windows->focused = NULL;
+	    redraw |= REDRAW_WIDGETS;
+	  }
+
+	  if(window != NULL) {
+	    /* If the mouse was clicked outside of the current window, we
+	       bring the clicked window to front. */
+	    if(dialog == NULL &&
+	       window != &desktop_window &&	   
+	       window != windows &&
+	       mouse_clicked) {
+	      /* Bring window to front. */
+	      ctk_window_open(window);
+	      redraw |= REDRAW_ALL;
+	    } else {
+	  
+	      /* Find out which widget currently is under the mouse pointer
+		 and give it focus, unless it already has focus. */
+	      mxc = mxc - window->x - 1;
+	      myc = myc - window->y - 1;      
+	    
+	      /* See if the mouse pointer is on a widget. If so, it should be
+		 selected and, if the button is clicked, activated. */
+	      for(widget = window->active; widget != NULL;
+		  widget = widget->next) {
+		if(mxc >= widget->x &&
+		   mxc <= widget->x + widget->w &&
+		   (myc == widget->y ||
+		    ((widget->type == CTK_WIDGET_BITMAP ||
+		      /*widget->type == CTK_WIDGET_TEXTMAP ||*/
+		      widget->type == CTK_WIDGET_ICON) &&
+		     (myc >= widget->y &&
+		      myc <= widget->y + ((struct ctk_bitmap *)widget)->h)))) {
+		  break;
+		}
+	      }
+	    
+	    
+	      if(mouse_moved) {
+		dispatcher_emit(ctk_signal_pointer_move, NULL,
+				window->owner);
+
+		
+
+		if(window->focused != NULL &&
+		   widget != window->focused) {
+		  add_redrawwidget(window->focused);
+		  if(CTK_WIDGET_TYPE(window->focused) ==
+		     CTK_WIDGET_TEXTENTRY) {
+		    ((struct ctk_textentry *)(window->focused))->state =
+		      CTK_TEXTENTRY_NORMAL;
+		  }
+		  window->focused = NULL;
+		}
+		redraw |= REDRAW_WIDGETS;
+		if(widget != NULL) {
+		  select_widget(widget);
+		}
+	      }
+	    
+	      if(mouse_button_changed) {
+		dispatcher_emit(ctk_signal_pointer_button,
+				(ek_data_t)mouse_button,
+				window->owner);
+		if(mouse_clicked && widget != NULL) {
+		  select_widget(widget);
+		  redraw |= activate(widget);
+		}
+	      }
+	    }
+	  }    
+	}
       }
     }
 #endif /* CTK_CONF_MOUSE_SUPPORT */
     
     while(ctk_arch_keyavail()) {
+
+      ctk_mouse_hide();
       
       screensaver_timer = 0;
       
-      c = ctk_arch_getkey();
-      
+      c = ctk_arch_getkey();      
       
       if(dialog != NULL) {
 	window = dialog;
@@ -1136,35 +1282,44 @@
 	redraw_widgetptr = 0;
       }
     }
-    if(redraw & REDRAW_ALL) {
-      do_redraw_all(1, height);
-#if CTK_CONF_MENUS
-    } else if(redraw & REDRAW_MENUPART) {
-      do_redraw_all(1, maxnitems + 1);
-    } else if(redraw & REDRAW_MENUS) {
-      ctk_draw_menus(&menus);
-#endif /* CTK_CONF_MENUS */
-    } else if(redraw & REDRAW_FOCUS) {
-      if(dialog != NULL) {
-	ctk_window_redraw(dialog);
-      } else if(windows != NULL) {
-	ctk_window_redraw(windows);	
-      } else {
-	ctk_window_redraw(&desktop_window);	
-      }
-    } else if(redraw & REDRAW_WIDGETS) {
-      for(i = 0; i < redraw_widgetptr; ++i) {
-	ctk_widget_redraw(redraw_widgets[i]);
-      }
-    }    
-    redraw = 0;
-    redraw_widgetptr = 0;
 #if CTK_CONF_WINDOWMOVE
   } else if(mode == CTK_MODE_WINDOWMOVE) {
 
     redraw = 0;
 
     window = windows;
+
+#if CTK_CONF_MOUSE_SUPPORT
+
+    /* If the mouse has moved, we move the window as well. */
+    if(mouse_moved) {
+
+      if(window->w + mxc + 2 >= width) {
+	window->x = width - 2 - window->w;
+      } else {
+	window->x = mxc;
+      }
+
+      if(window->h + myc + 2 >= height) {
+	window->y = height - 2 - window->h;
+      } else {
+	window->y = myc;
+      }
+      if(window->y > 0) {
+	--window->y;
+      }
+
+      redraw = REDRAW_ALL;
+    }		  
+    
+    /* Check if the mouse has been clicked, and stop moving the window
+       if so. */
+    if(mouse_button_changed &&
+       mouse_button == 0) {
+      mode = CTK_MODE_NORMAL;
+      redraw = REDRAW_ALL;      
+    }
+#endif /* CTK_CONF_MOUSE_SUPPORT */
     
     while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
     
@@ -1206,12 +1361,37 @@
 	break;
       }
     }
-    if(redraw & REDRAW_ALL) {
+    /*    if(redraw & REDRAW_ALL) {
       do_redraw_all(1, height);
     }
-    redraw = 0;
+    redraw = 0;*/
 #endif /* CTK_CONF_WINDOWMOVE */
   }
+
+  if(redraw & REDRAW_ALL) {
+    do_redraw_all(1, height);
+#if CTK_CONF_MENUS
+  } else if(redraw & REDRAW_MENUPART) {
+    do_redraw_all(1, maxnitems + 1);
+  } else if(redraw & REDRAW_MENUS) {
+    ctk_draw_menus(&menus);
+#endif /* CTK_CONF_MENUS */
+  } else if(redraw & REDRAW_FOCUS) {
+    if(dialog != NULL) {
+      ctk_window_redraw(dialog);
+    } else if(windows != NULL) {
+      ctk_window_redraw(windows);	
+    } else {
+      ctk_window_redraw(&desktop_window);	
+    }
+  } else if(redraw & REDRAW_WIDGETS) {
+    for(i = 0; i < redraw_widgetptr; ++i) {
+      ctk_widget_redraw(redraw_widgets[i]);
+    }
+  }    
+  redraw = 0;
+  redraw_widgetptr = 0;
+  
 }
 /*-----------------------------------------------------------------------------------*/
 static