diff src/toolbar-msw.c @ 278:90d73dddcdc4 r21-0b37

Import from CVS: tag r21-0b37
author cvs
date Mon, 13 Aug 2007 10:31:29 +0200
parents 6330739388db
children 7df0dd720c89
line wrap: on
line diff
--- a/src/toolbar-msw.c	Mon Aug 13 10:30:38 2007 +0200
+++ b/src/toolbar-msw.c	Mon Aug 13 10:31:29 2007 +0200
@@ -31,6 +31,7 @@
 #include "toolbar.h"
 #include "window.h"
 #include "gui.h"
+#include "elhash.h"
 #include "console-msw.h"
 #include "glyphs-msw.h"
 #include "objects-msw.h"
@@ -39,9 +40,13 @@
 #define TOOLBAR_ITEM_ID_MIN 0x4000
 #define TOOLBAR_ITEM_ID_MAX 0x7FFF
 #define TOOLBAR_ITEM_ID_BITS(x) (((x) & 0x3FFF) | 0x4000)
+#define TOOLBAR_ID_BIAS 16
+#define TOOLBAR_HANDLE(f,p) \
+GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + p)
 #ifndef TB_SETIMAGELIST
 #define TB_SETIMAGELIST (WM_USER + 48)
 #define TB_GETIMAGELIST (WM_USER + 49)
+#define TB_SETPADDING   (WM_USER + 87)
 #endif
 
 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag)			\
@@ -66,7 +71,8 @@
   } while (0)
 
 static int
-allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button)
+allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button,
+			  enum toolbar_pos pos)
 {
   /* hmm what do we generate an id based on */
   int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
@@ -83,24 +89,37 @@
 			 int thickness_change)
 {
   HIMAGELIST ilist=NULL;
-  if (FRAME_MSWINDOWS_TOOLBAR (f))
+  int i;
+  HWND toolbarwnd = TOOLBAR_HANDLE(f, pos);
+  if (toolbarwnd)
     {
-      /* get the image list and delete it */
-      SendMessage (FRAME_MSWINDOWS_TOOLBAR (f), 
-		   TB_GETIMAGELIST, 0, 
-		   (LONG) &ilist);
+      TBBUTTON info;
       
-      /* destroy the toolbar window */
-      DestroyWindow (FRAME_MSWINDOWS_TOOLBAR (f));
-      FRAME_MSWINDOWS_TOOLBAR (f) = 0;
-      
+      /* delete the buttons and remove the command from the hashtable*/
+      i = SendMessage (toolbarwnd, TB_BUTTONCOUNT, 0, 0);
+      for (i--; i >= 0; i--)
+	{
+	  SendMessage (toolbarwnd, TB_GETBUTTON, (WPARAM)i, 
+		       (LPARAM)&info);
+	  Fremhash(make_int(info.idCommand), 
+		   FRAME_MSWINDOWS_TOOLBAR_HASHTABLE(f));
+	  SendMessage (toolbarwnd, TB_DELETEBUTTON, (WPARAM)i, 0);
+	}
+	  
       /* finally get rid of the image list assuming it clears up its
          bitmaps */
+      SendMessage (toolbarwnd, TB_GETIMAGELIST, 0, (LONG) &ilist);
       if (ilist)
 	{
 	  ImageList_Destroy(ilist);
 	}
+      SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, (LPARAM)NULL);
+
+      ShowWindow(toolbarwnd, SW_HIDE);
     }
+
+  FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=0;
+  SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
 }
 
 static void
@@ -111,24 +130,34 @@
   int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
   Lisp_Object button, window, glyph, instance;
   int nbuttons=0;
+  int shadow_thickness = 2;	/* get this from somewhere else? */
+  int window_frame_width = 3;
+  unsigned int checksum=0;
   struct window *w;
   TBBUTTON* button_tbl, *tbbutton;
   HIMAGELIST ilist=NULL;
+  HWND toolbarwnd=NULL;
 
   get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
+
+  if (x==1)
+    x=0;
+
   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
   w = XWINDOW (window);
 
+  toolbarwnd = TOOLBAR_HANDLE(f,pos);
+  
   /* set button sizes based on bar size */
   if (vert)
     {
-      width = height = bar_width - border_width * 2;
-      bmwidth = bmheight = width -2;
+      width = height = bar_width;
+      bmwidth = bmheight = width - (border_width + shadow_thickness) * 2;
     }
   else
     {
-      height = width = bar_height - border_width * 2;
-      bmwidth = bmheight = width -2;
+      height = width = bar_height - window_frame_width * 2; 
+      bmwidth = bmheight = width - (border_width + shadow_thickness) * 2; 
     }
 
   button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
@@ -140,132 +169,249 @@
   while (!NILP (button))
     {
       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+      checksum = HASH3 (checksum, 
+			internal_hash (get_toolbar_button_glyph(w, tb), 0),
+			internal_hash (tb->callback, 0));
       button = tb->next;
       nbuttons++;
     }
 
-  /* build up the data required by win32 fns. */
-  button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
-  button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
-  tbbutton = button_tbl;
-
-  while (!NILP (button))
+  /* only rebuild if something has changed */
+  if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
     {
-      struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+      /* remove the old one */
+      mswindows_clear_toolbar (f, pos, 0);
 
-      tbbutton->idCommand = allocate_toolbar_item_id (f, tb);
-      tbbutton->fsState=tb->enabled ? TBSTATE_ENABLED : TBSTATE_INDETERMINATE;
-      tbbutton->fsStyle=tb->blank ? TBSTYLE_SEP : TBSTYLE_BUTTON;
-      tbbutton->dwData=0; 
-      tbbutton->iString=0;
-      
-      /* mess with the button image */
-      glyph = get_toolbar_button_glyph (w, tb);
+      FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=checksum;
 
-      if (GLYPHP (glyph))
-	instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
-      else
-	instance = Qnil;
-
-      if (IMAGE_INSTANCEP (instance))
-	{
-	  struct Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
+      /* build up the data required by win32 fns. */
+      button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
+      button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
+      tbbutton = button_tbl;
 
-	  if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
+      while (!NILP (button))
+	{
+	  struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+	  
+	  tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
+	  tbbutton->fsState=tb->enabled ? TBSTATE_ENABLED 
+	    : TBSTATE_INDETERMINATE;
+	  tbbutton->fsStyle=tb->blank ? TBSTYLE_SEP : TBSTYLE_BUTTON;
+	  tbbutton->dwData=0; 
+	  tbbutton->iString=0;
+	  
+	  /* note that I am not doing the button size here. This is
+             because it is slightly out of my control and the main
+             place they are used is in redisplay for getting events
+             over toolbar buttons. Since the right way to do help echo
+             is with tooltips I'm not going to bother with the extra
+             work involved. */
+	  
+	  /* mess with the button image */
+	  glyph = get_toolbar_button_glyph (w, tb);
+	  
+	  if (GLYPHP (glyph))
+	    instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
+	  else
+	    instance = Qnil;
+	  
+	  if (IMAGE_INSTANCEP (instance))
 	    {
-	      /* we are going to honour the toolbar settings and
-		 resize the bitmaps accordingly */
+	      struct Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
 	      
-	      if ((IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth
-		   ||
-		   IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
-		  &&
-		  !mswindows_resize_dibitmap_instance (p, f, 
-						       bmwidth, bmheight))
+	      if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
 		{
-		  xfree (button_tbl);
-		  if (ilist) ImageList_Destroy (ilist);
-		  signal_simple_error ("couldn't resize pixmap", 
-				       instance);
-		}
+		  /* we are going to honour the toolbar settings and
+		     resize the bitmaps accordingly */
+		  
+		  if (IMAGE_INSTANCE_PIXMAP_WIDTH (p) > bmwidth
+		      ||
+		      IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > bmheight)
+		    {
+		      if (!mswindows_resize_dibitmap_instance 
+			  (p, f, bmwidth, bmheight))
+			{
+			  xfree (button_tbl);
+			  if (ilist) ImageList_Destroy (ilist);
+			  signal_simple_error ("couldn't resize pixmap", 
+					       instance);
+			}
+		    }
+		  else 
+		    {
+		      bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
+		      bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
+		    }
 	      
-	      /* need to build an image list for the bitmaps */
-	      if (!ilist)
-		{
-		  if (!(ilist = ImageList_Create 
-			( IMAGE_INSTANCE_PIXMAP_WIDTH (p),
-			  IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
-			  ILC_COLOR24, 	
-			  nbuttons,
-			  nbuttons * 2 )))
+		  /* need to build an image list for the bitmaps */
+		  if (!ilist)
+		    {
+		      if (!(ilist = ImageList_Create 
+			    ( IMAGE_INSTANCE_PIXMAP_WIDTH (p),
+			      IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
+			      ILC_COLOR24, 	
+			      nbuttons,
+			      nbuttons * 2 )))
+			{
+			  xfree (button_tbl);
+			  signal_simple_error ("couldn't create image list",
+					       instance);
+			}
+		    }
+  
+		  /* add a bitmap to the list */
+		  if ((tbbutton->iBitmap =
+		       ImageList_Add (ilist, 
+				      IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
+				      IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
 		    {
 		      xfree (button_tbl);
-		      signal_simple_error ("couldn't create image list",
+		      if (ilist) ImageList_Destroy (ilist);
+		      signal_simple_error ("image list creation failed", 
 					   instance);
 		    }
 		}
-  
-	      /* add a bitmap to the list */
-	      if ((tbbutton->iBitmap =
-		   ImageList_Add (ilist, 
-				  IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
-				  IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
-		{
-		  xfree (button_tbl);
-		  if (ilist) ImageList_Destroy (ilist);
-		  signal_simple_error ("image list creation failed", 
-				       instance);
-		}
 	    }
+
+	  Fputhash (make_int (tbbutton->idCommand), 
+		    button, FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f));
+      
+	  tbbutton++;
+	  button = tb->next;
+	}
+
+      button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
+
+  /* create the toolbar window? */
+      if (!toolbarwnd 
+	  &&
+	  (toolbarwnd = 
+	   CreateWindowEx ( WS_EX_WINDOWEDGE,
+			    TOOLBARCLASSNAME,
+			    NULL,
+			    WS_CHILD | WS_VISIBLE | WS_DLGFRAME | TBSTYLE_TOOLTIPS 
+			    | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER,
+			    x, y, bar_width, bar_height,
+			    FRAME_MSWINDOWS_HANDLE (f),
+			    (HMENU)(TOOLBAR_ID_BIAS + pos),
+			    NULL, 
+			    NULL))==NULL)
+	{
+	  xfree (button_tbl);
+	  ImageList_Destroy (ilist);
+	  error ("couldn't create toolbar");
+	}
+#if 0
+      SendMessage (toolbarwnd, TB_SETPADDING,
+		   0, MAKELPARAM(border_width, border_width));
+#endif
+      /* finally populate with images */
+      if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
+		       (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1) 
+	{
+	  mswindows_clear_toolbar (f, pos, 0);
+	  error ("couldn't set button structure size");
+	}
+
+      /* set the size of buttons */
+      SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0, 
+		   (LPARAM)MAKELONG (width, height));
+		   
+      /* set the size of bitmaps */
+      SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0, 
+		   (LPARAM)MAKELONG (bmwidth, bmheight));
+		   
+      /* finally populate with images */
+      if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
+			(WPARAM)nbuttons, (LPARAM)button_tbl))
+	{
+	  mswindows_clear_toolbar (f, pos, 0);
+	  error ("couldn't add button list to toolbar");
+	}
+
+      /* vertical toolbars need more rows */
+      if (vert)
+	{
+	  SendMessage (toolbarwnd, TB_SETROWS, 
+		       MAKEWPARAM(nbuttons, FALSE), 0);
+	}
+
+      else
+	{
+	  SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE), 0);
 	}
 
-      Fputhash (make_int (tbbutton->idCommand), 
-		tb->callback, FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f));
-      
-      tbbutton++;
-      button = tb->next;
-    }
+      /* finally populate with images */
+      if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
+		       (LPARAM)ilist) == -1) 
+	{
+	  mswindows_clear_toolbar (f, pos, 0);
+	  error ("couldn't add image list to toolbar");
+	}
 
-  button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
+      /* now display the window */
+      ShowWindow (toolbarwnd, SW_SHOW);
 
-  /* now create the toolbar ... */
-  if ((FRAME_MSWINDOWS_TOOLBAR (f) =
-       CreateToolbarEx (FRAME_MSWINDOWS_HANDLE (f),
-			TBSTYLE_ALTDRAG | WS_CHILD,
-			NULL,
-			nbuttons, 	
-			0,
-			0, 	
-			button_tbl,
-			nbuttons, 	
-			width, height,
-			bmwidth, bmheight, 	
-			sizeof(TBBUTTON) )) == NULL)
+      if (button_tbl) xfree (button_tbl);
+
+      SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
+    }
+}
+
+static void
+mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos)
+{
+  int bar_x, bar_y, bar_width, bar_height, vert;
+  HWND toolbarwnd = TOOLBAR_HANDLE(f,pos);
+  
+  if (toolbarwnd)
     {
-      xfree (button_tbl);
-      ImageList_Destroy (ilist);
-      error ("couldn't create toolbar");
-    }
+      get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
+			  &vert, 1);
 
-  /* finally populate with images */
-  if (SendMessage (FRAME_MSWINDOWS_TOOLBAR (f), TB_SETIMAGELIST, NULL,
-		   (LPARAM)ilist) == -1) 
-    {
-      mswindows_clear_toolbar (f, pos, 0);
-      error ("couldn't add image list to toolbar");
+      /* #### This terrible mangling with coordinates perhaps
+	 arises from different treatment of toolbar positions
+	 by Windows and by XEmacs. */
+      switch (pos)
+	{
+	case TOP_TOOLBAR:
+	  bar_x -= 2; bar_y--;
+	  bar_width += 2; bar_height++;
+	  break;
+	case LEFT_TOOLBAR:
+	  bar_x -= 2; bar_y--;
+	  bar_width++; bar_height++;
+	  break;
+	case BOTTOM_TOOLBAR:
+	  bar_x--;
+	  bar_width++;
+	  break;
+	case RIGHT_TOOLBAR:
+	  bar_y--;
+	  break;
+	}
+      SetWindowPos (toolbarwnd, NULL, bar_x, bar_y, 
+		    bar_width + 1, bar_height + 1, SWP_NOZORDER);
     }
+}
 
-  /* now move the window */
-  SetWindowPos (FRAME_MSWINDOWS_TOOLBAR (f), HWND_TOP, x, y, 
-		bar_width, bar_height,
-		SWP_SHOWWINDOW);
-#if 0
-  ShowWindow (FRAME_MSWINDOWS_TOOLBAR (f), SW_SHOWNORMAL);
-#endif
+static void
+mswindows_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
+				   int height)
+{
+  assert (FRAME_MSWINDOWS_P (f));
+
+  if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
+    mswindows_move_toolbar (f, TOP_TOOLBAR);
 
-  if (button_tbl) xfree (button_tbl);
+  if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
+    mswindows_move_toolbar (f, BOTTOM_TOOLBAR);
 
-  SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
+  if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
+    mswindows_move_toolbar (f, LEFT_TOOLBAR);
+
+  if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
+    mswindows_move_toolbar (f, RIGHT_TOOLBAR);
 }
 
 static void
@@ -303,7 +449,51 @@
 static void
 mswindows_free_frame_toolbars (struct frame *f)
 {
-  mswindows_clear_toolbar(f, 0, 0);
+  HWND twnd=NULL;
+#define DELETE_TOOLBAR(pos) \
+  mswindows_clear_toolbar(f, 0, pos); \
+  if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + pos))) \
+      DestroyWindow(twnd)
+
+  DELETE_TOOLBAR(TOP_TOOLBAR);
+  DELETE_TOOLBAR(BOTTOM_TOOLBAR);
+  DELETE_TOOLBAR(LEFT_TOOLBAR);
+  DELETE_TOOLBAR(RIGHT_TOOLBAR);
+#undef DELETE_TOOLBAR
+}
+
+/* map toolbar hwnd to pos*/
+int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
+{
+#if 1
+  int id = GetDlgCtrlID(ctrl);
+  return id ? id - TOOLBAR_ID_BIAS : -1;
+#else
+  if (GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS) == ctrl)
+    return 0;
+  else if (GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS +1) == ctrl)
+    return 1;
+  else if (GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS +2) == ctrl)
+    return 2;
+  else if (GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS +3) == ctrl)
+    return 3;
+  else
+    assert(0);
+#endif
+}
+
+Lisp_Object 
+mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
+{
+  Lisp_Object button = Fgethash (make_int (command_id),
+				 FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f), Qnil);
+  
+  if (!NILP (button))
+    {
+      struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+      return tb->help_string;
+    }
+  return Qnil;
 }
 
 /*
@@ -313,19 +503,23 @@
  * command if we return nil
  */
 Lisp_Object
-mswindows_handle_toolbar_wm_command (struct frame* f, WORD id)
+mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
 {
   /* Try to map the command id through the proper hash table */
-  Lisp_Object command, funcsym, frame;
+  Lisp_Object button, command, funcsym, frame;
   struct gcpro gcpro1;
+  
+  button = Fgethash (make_int (id), 
+		     FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f), Qnil);
 
-  command = Fgethash (make_int (id), 
-		      FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f), Qunbound);
-  if (UNBOUNDP (command))
-    {
-      return Qnil;
-    }
+  if (NILP (button))
+    return Qnil;
 
+  command = XTOOLBAR_BUTTON(button)->callback;
+  
+  if (UNBOUNDP(command))
+    return Qnil;
+  
   /* Need to gcpro because the hashtable may get destroyed
      by menu_cleanup(), and will not gcpro the command
      any more */
@@ -363,5 +557,6 @@
   CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
   CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
   CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
+  CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);
 }