Mercurial > hg > xemacs-beta
diff src/toolbar-msw.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 8de8e3f6228a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolbar-msw.c Mon Aug 13 11:28:15 2007 +0200 @@ -0,0 +1,654 @@ +/* toolbar implementation -- mswindows interface. + Copyright (C) 1995 Board of Trustees, University of Illinois. + Copyright (C) 1995 Sun Microsystems, Inc. + Copyright (C) 1995, 1996 Ben Wing. + Copyright (C) 1996 Chuck Thompson. + Copyright (C) 1998 Andy Piper. + +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 "elhash.h" +#include "console-msw.h" +#include "glyphs-msw.h" +#include "objects-msw.h" + +#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_SETDISABLEDIMAGELIST (WM_USER + 54) +#define TB_GETDISABLEDIMAGELIST (WM_USER + 55) +#endif +#ifndef TB_SETPADDING +#define TB_SETPADDING (WM_USER + 87) +#endif +#define MSWINDOWS_BUTTON_SHADOW_THICKNESS 2 +#define MSWINDOWS_BLANK_SIZE 5 +#define MSWINDOWS_MINIMUM_TOOLBAR_SIZE 8 + +static void +mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos); + +#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, + enum toolbar_pos pos) +{ + /* 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_HASH_TABLE (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; + int i; + HWND toolbarwnd = TOOLBAR_HANDLE(f, pos); + if (toolbarwnd) + { + TBBUTTON info; + + /* Delete the buttons and remove the command from the hash table*/ + 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_HASH_TABLE(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 +mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos) +{ + int x, y, bar_width, bar_height, vert; + int width=-1, height=-1, bmwidth=0, bmheight=0, maxbmwidth, maxbmheight; + int style_3d=0; + int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos); + Lisp_Object button, glyph, instance; + Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f); + + int nbuttons=0; + int shadow_thickness = 2; /* get this from somewhere else? */ + int window_frame_width = 3; + int padding = (border_width + shadow_thickness) * 2; + unsigned int checksum=0; + struct window *w = XWINDOW (window); + TBBUTTON* button_tbl, *tbbutton; + HIMAGELIST ilist=NULL; + HWND toolbarwnd=NULL; + + get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0); + + /* ediff bogusly sets the height to 2 for some obscure X-specific + reason. This ensures that we only try and output a toolbar for + sensible sizes */ + if (bar_width < MSWINDOWS_MINIMUM_TOOLBAR_SIZE + || + bar_height < MSWINDOWS_MINIMUM_TOOLBAR_SIZE) + { + return; + } + + if (x==1) + x=0; + + toolbarwnd = TOOLBAR_HANDLE (f,pos); + + /* set button sizes based on bar size */ + if (vert) + { + if (style_3d) + { + width = height = bar_width + - (window_frame_width + shadow_thickness) * 2; + } + else + width = height = bar_width; + + maxbmwidth = maxbmheight = width - padding; + } + else + { + if (style_3d) + { + height = width = bar_height + - (window_frame_width + shadow_thickness) * 2; + } + else + width = height = bar_height; + + maxbmwidth = maxbmheight = width - padding; + } + + button = FRAME_TOOLBAR_BUTTONS (f, pos); + + /* 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); + checksum = HASH5 (checksum, + internal_hash (get_toolbar_button_glyph(w, tb), 0), + internal_hash (tb->callback, 0), + width, + LISP_HASH (w->toolbar_buttons_captioned_p)); + button = tb->next; + nbuttons++; + } + + /* only rebuild if something has changed */ + if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum) + { + /* remove the old one */ + mswindows_clear_toolbar (f, pos, 0); + + FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=checksum; + + /* build up the data required by win32 fns. */ + button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons); + button = FRAME_TOOLBAR_BUTTONS (f, pos); + tbbutton = button_tbl; + + while (!NILP (button)) + { + struct toolbar_button *tb = XTOOLBAR_BUTTON (button); + HBITMAP bitmap=NULL, mask=NULL; + bitmap=mask=NULL; + + if (tb->blank) + tbbutton->fsStyle = TBSTYLE_SEP; + else + { + tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos); + /* currently we output the toolbar again with disabled + buttons it might be good to use the ms disabled code + instead but that means another image list, so we'll stick + with the emacs model. */ + tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED : + TBSTATE_INDETERMINATE; + tbbutton->fsStyle = 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 honor the toolbar settings + and resize the bitmaps accordingly if they are + too big. If they are too small we leave them + and pad the difference - unless a different size + crops up in the middle, at which point we *have* + to resize since the ImageList won't cope.*/ + + if ((bmwidth + && + IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth) + || + (bmheight + && + IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight) + || + IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth + || + IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight) + { + if (!bmheight) + bmheight = min (maxbmheight, + IMAGE_INSTANCE_PIXMAP_HEIGHT (p)); + if (!bmwidth) + bmwidth = min (maxbmwidth, + IMAGE_INSTANCE_PIXMAP_WIDTH (p)); + + if (! (bitmap = mswindows_create_resized_bitmap + (p, f, bmwidth, bmheight))) + { + xfree (button_tbl); + if (ilist) ImageList_Destroy (ilist); + signal_simple_error ("Couldn't resize pixmap", + instance); + } + /* we don't care if the mask fails */ + mask = mswindows_create_resized_mask + (p, f, bmwidth, bmheight); + } + else + { + if (!bmwidth) + bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p); + if (!bmheight) + bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p); + } + + /* need to build an image list for the bitmaps */ + if (!ilist && !(ilist = ImageList_Create + ( bmwidth, bmheight, + (IMAGE_INSTANCE_MSWINDOWS_MASK (p) + ? ILC_MASK : 0) | ILC_COLOR24, + nbuttons, nbuttons * 2 ))) + { + xfree (button_tbl); + signal_simple_error ("Couldn't create image list", + instance); + } + + /* make the mask actually do something */ + ImageList_SetBkColor (ilist, CLR_NONE); + /* add a bitmap to the list */ + if ((tbbutton->iBitmap = + ImageList_Add + (ilist, + bitmap ? bitmap + : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p), + mask ? mask + : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0) + { + xfree (button_tbl); + if (ilist) ImageList_Destroy (ilist); + signal_simple_error + ("couldn't add image to image list", instance); + } + /* we're done with these now */ + DeleteObject (bitmap); + DeleteObject (mask); + } + } + + Fputhash (make_int (tbbutton->idCommand), + button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f)); + } + + /* now fix up the button size */ + tb->x = x; + tb->y = y; + tb->vertical = vert; + tb->border_width = border_width; + tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2; + tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2; + + if (tb->blank) + { + if (vert) + tb->height = MSWINDOWS_BLANK_SIZE; + else + tb->width = MSWINDOWS_BLANK_SIZE; + } + + if (vert) + y += tb->height; + else + x += tb->width; + /* move on to the next button */ + tbbutton++; + button = tb->next; + } + + button = FRAME_TOOLBAR_BUTTONS (f, pos); + + /* create the toolbar window? */ + if (!toolbarwnd + && + (toolbarwnd = + CreateWindowEx ( WS_EX_WINDOWEDGE, + TOOLBARCLASSNAME, + NULL, + WS_CHILD | WS_VISIBLE + | (style_3d ? WS_DLGFRAME : 0) + | 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"); + } + + /* 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"); + } + + if (vert) + height = min (bmheight + padding, height); + else + width = min (bmwidth + padding, width); + + /* pad the buttons */ + SendMessage (toolbarwnd, TB_SETPADDING, + 0, MAKELPARAM(width - bmwidth, height - bmheight)); + + /* 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)); + + /* tell it we've done it */ + SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0); + + /* 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) + { + RECT tmp; + SendMessage (toolbarwnd, TB_SETROWS, + MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp); + } + + else + { + RECT tmp; + SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE), + (LPARAM)&tmp); + } + + /* finally populate with images */ + if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, + (LPARAM)ilist) < 0 + || + SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0, + (LPARAM)ilist) < 0) + { + mswindows_clear_toolbar (f, pos, 0); + error ("couldn't add image list to toolbar"); + } + + /* now display the window */ + ShowWindow (toolbarwnd, SW_SHOW); + /* no idea why this is necessary but initial display will not + happen otherwise. */ + mswindows_move_toolbar (f, pos); + + 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) + { + get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height, + &vert, 1); + + /* #### 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--; bar_y-=2; + bar_width+=3; bar_height+=3; + break; + case LEFT_TOOLBAR: + bar_x--; bar_y-=2; + bar_height++; bar_width++; + break; + case BOTTOM_TOOLBAR: + bar_y-=2; + bar_width+=4; bar_height+=4; + break; + case RIGHT_TOOLBAR: + bar_y-=2; bar_x++; + bar_width++; bar_height++; + break; + } + SetWindowPos (toolbarwnd, NULL, bar_x, bar_y, + bar_width, bar_height, SWP_NOZORDER); + } +} + +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 (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)) + mswindows_move_toolbar (f, BOTTOM_TOOLBAR); + + 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 +mswindows_redraw_frame_toolbars (struct frame *f) +{ + mswindows_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f), + FRAME_PIXHEIGHT (f)); +} + +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) +{ + 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) +{ + int id = GetDlgCtrlID(ctrl); + return id ? id - TOOLBAR_ID_BIAS : -1; +} + +Lisp_Object +mswindows_get_toolbar_button_text ( struct frame* f, int command_id ) +{ + Lisp_Object button = Fgethash (make_int (command_id), + FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil); + + if (!NILP (button)) + { + struct toolbar_button *tb = XTOOLBAR_BUTTON (button); + return tb->help_string; + } + return Qnil; +} + +/* + * 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, HWND ctrl, WORD id) +{ + /* Try to map the command id through the proper hash table */ + Lisp_Object button, data, fn, arg, frame; + + button = Fgethash (make_int (id), + FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil); + + if (NILP (button)) + return Qnil; + + data = XTOOLBAR_BUTTON (button)->callback; + + /* #### ? */ + if (UNBOUNDP (data)) + return Qnil; + + /* Ok, this is our one. Enqueue it. */ + get_gui_callback (data, &fn, &arg); + XSETFRAME (frame, f); + mswindows_enqueue_misc_user_event (frame, fn, arg); + + 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); + CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars); + CONSOLE_HAS_METHOD (mswindows, redraw_frame_toolbars); +} +