diff src/toolbar-msw.c @ 276:6330739388db r21-0b36

Import from CVS: tag r21-0b36
author cvs
date Mon, 13 Aug 2007 10:30:37 +0200
parents
children 90d73dddcdc4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/toolbar-msw.c	Mon Aug 13 10:30:37 2007 +0200
@@ -0,0 +1,367 @@
+/* toolbar implementation -- mswindows interface.
+   Copyright (C) 1998 Free Software Foundation.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This implementation by Andy Piper <andyp@parallax.co.uk>, with bits
+   borrowed from toolbar-x.c */
+
+/* Synched up with: Not in FSF. */
+
+#include <config.h>
+#include "lisp.h"
+
+#include "faces.h"
+#include "frame.h"
+#include "toolbar.h"
+#include "window.h"
+#include "gui.h"
+#include "console-msw.h"
+#include "glyphs-msw.h"
+#include "objects-msw.h"
+
+/* Why did Kirill choose this range ? */
+#define TOOLBAR_ITEM_ID_MIN 0x4000
+#define TOOLBAR_ITEM_ID_MAX 0x7FFF
+#define TOOLBAR_ITEM_ID_BITS(x) (((x) & 0x3FFF) | 0x4000)
+#ifndef TB_SETIMAGELIST
+#define TB_SETIMAGELIST (WM_USER + 48)
+#define TB_GETIMAGELIST (WM_USER + 49)
+#endif
+
+#define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag)			\
+  do {									\
+    switch (pos)							\
+      {									\
+      case TOP_TOOLBAR:							\
+	(frame)->top_toolbar_was_visible = flag;			\
+	break;								\
+      case BOTTOM_TOOLBAR:						\
+	(frame)->bottom_toolbar_was_visible = flag;			\
+	break;								\
+      case LEFT_TOOLBAR:						\
+	(frame)->left_toolbar_was_visible = flag;			\
+	break;								\
+      case RIGHT_TOOLBAR:						\
+	(frame)->right_toolbar_was_visible = flag;			\
+	break;								\
+      default:								\
+	abort ();							\
+      }									\
+  } while (0)
+
+static int
+allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button)
+{
+  /* hmm what do we generate an id based on */
+  int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
+  while (!NILP (Fgethash (make_int (id),
+			  FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f), Qnil)))
+    {
+      id = TOOLBAR_ITEM_ID_BITS (id + 1);
+    }
+  return id;
+}
+
+static void
+mswindows_clear_toolbar (struct frame *f, enum toolbar_pos pos,
+			 int thickness_change)
+{
+  HIMAGELIST ilist=NULL;
+  if (FRAME_MSWINDOWS_TOOLBAR (f))
+    {
+      /* get the image list and delete it */
+      SendMessage (FRAME_MSWINDOWS_TOOLBAR (f), 
+		   TB_GETIMAGELIST, 0, 
+		   (LONG) &ilist);
+      
+      /* destroy the toolbar window */
+      DestroyWindow (FRAME_MSWINDOWS_TOOLBAR (f));
+      FRAME_MSWINDOWS_TOOLBAR (f) = 0;
+      
+      /* finally get rid of the image list assuming it clears up its
+         bitmaps */
+      if (ilist)
+	{
+	  ImageList_Destroy(ilist);
+	}
+    }
+}
+
+static void
+mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos)
+{
+  int x, y, bar_width, bar_height, vert;
+  int width=-1, height=-1, bmwidth=-1, bmheight=-1;
+  int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
+  Lisp_Object button, window, glyph, instance;
+  int nbuttons=0;
+  struct window *w;
+  TBBUTTON* button_tbl, *tbbutton;
+  HIMAGELIST ilist=NULL;
+
+  get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
+  window = FRAME_LAST_NONMINIBUF_WINDOW (f);
+  w = XWINDOW (window);
+
+  /* set button sizes based on bar size */
+  if (vert)
+    {
+      width = height = bar_width - border_width * 2;
+      bmwidth = bmheight = width -2;
+    }
+  else
+    {
+      height = width = bar_height - border_width * 2;
+      bmwidth = bmheight = width -2;
+    }
+
+  button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
+
+  /* First loop over all of the buttons to determine how many there
+     are. This loop will also make sure that all instances are
+     instantiated so when we actually output them they will come up
+     immediately. */
+  while (!NILP (button))
+    {
+      struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+      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))
+    {
+      struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+
+      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);
+
+      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);
+
+	  if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
+	    {
+	      /* 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)
+		  &&
+		  !mswindows_resize_dibitmap_instance (p, f, 
+						       bmwidth, bmheight))
+		{
+		  xfree (button_tbl);
+		  if (ilist) ImageList_Destroy (ilist);
+		  signal_simple_error ("couldn't resize pixmap", 
+				       instance);
+		}
+	      
+	      /* 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);
+		  if (ilist) ImageList_Destroy (ilist);
+		  signal_simple_error ("image list creation failed", 
+				       instance);
+		}
+	    }
+	}
+
+      Fputhash (make_int (tbbutton->idCommand), 
+		tb->callback, FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f));
+      
+      tbbutton++;
+      button = tb->next;
+    }
+
+  button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons;
+
+  /* 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)
+    {
+      xfree (button_tbl);
+      ImageList_Destroy (ilist);
+      error ("couldn't create toolbar");
+    }
+
+  /* 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");
+    }
+
+  /* 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
+
+  if (button_tbl) xfree (button_tbl);
+
+  SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
+}
+
+static void
+mswindows_initialize_frame_toolbars (struct frame *f)
+{
+
+}
+
+static void
+mswindows_output_frame_toolbars (struct frame *f)
+{
+  assert (FRAME_MSWINDOWS_P (f));
+
+  if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
+    mswindows_output_toolbar (f, TOP_TOOLBAR);
+  else if (f->top_toolbar_was_visible)
+    mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
+
+  if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
+    mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
+  else if (f->bottom_toolbar_was_visible)
+    mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
+
+  if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
+    mswindows_output_toolbar (f, LEFT_TOOLBAR);
+  else if (f->left_toolbar_was_visible)
+    mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
+
+  if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
+    mswindows_output_toolbar (f, RIGHT_TOOLBAR);
+  else if (f->right_toolbar_was_visible)
+    mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
+}
+
+static void
+mswindows_free_frame_toolbars (struct frame *f)
+{
+  mswindows_clear_toolbar(f, 0, 0);
+}
+
+/*
+ * Return value is Qt if we have dispatched the command,
+ * or Qnil if id has not been mapped to a callback.
+ * Window procedure may try other targets to route the
+ * command if we return nil
+ */
+Lisp_Object
+mswindows_handle_toolbar_wm_command (struct frame* f, WORD id)
+{
+  /* Try to map the command id through the proper hash table */
+  Lisp_Object command, funcsym, frame;
+  struct gcpro gcpro1;
+
+  command = Fgethash (make_int (id), 
+		      FRAME_MSWINDOWS_TOOLBAR_HASHTABLE (f), Qunbound);
+  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 */
+  GCPRO1 (command);
+  
+  /* Ok, this is our one. Enqueue it. */
+  if (SYMBOLP (command))
+      funcsym = Qcall_interactively;
+  else if (CONSP (command))
+      funcsym = Qeval;
+  else
+    signal_simple_error ("Callback must be either evallable form or a symbol",
+			 command);
+
+  XSETFRAME (frame, f);
+  enqueue_misc_user_event (frame, funcsym, command);
+
+  /* Needs good bump also, for WM_COMMAND may have been dispatched from
+     mswindows_need_event, which will block again despite new command
+     event has arrived */
+  mswindows_bump_queue ();
+  
+  UNGCPRO; /* command */
+  return Qt;
+}
+
+
+/************************************************************************/
+/*                            initialization                            */
+/************************************************************************/
+
+void
+console_type_create_toolbar_mswindows (void)
+{
+  CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
+  CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
+  CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
+}
+