1 /* toolbar implementation -- mswindows interface.
2 Copyright (C) 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1995, 1996 Ben Wing.
5 Copyright (C) 1996 Chuck Thompson.
6 Copyright (C) 1998 Andy Piper.
8 This file is part of XEmacs.
10 XEmacs is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License
21 along with XEmacs; see the file COPYING. If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
25 /* This implementation by Andy Piper <andyp@parallax.co.uk>, with bits
26 borrowed from toolbar-x.c */
28 /* Synched up with: Not in FSF. */
39 #include "console-msw.h"
40 #include "glyphs-msw.h"
41 #include "objects-msw.h"
43 #define TOOLBAR_ITEM_ID_MIN 0x4000
44 #define TOOLBAR_ITEM_ID_MAX 0x7FFF
45 #define TOOLBAR_ITEM_ID_BITS(x) (((x) & 0x3FFF) | 0x4000)
46 #define TOOLBAR_ID_BIAS 16
47 #define TOOLBAR_HANDLE(f,p) \
48 GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + p)
49 #ifndef TB_SETIMAGELIST
50 #define TB_SETIMAGELIST (WM_USER + 48)
51 #define TB_GETIMAGELIST (WM_USER + 49)
52 #define TB_SETDISABLEDIMAGELIST (WM_USER + 54)
53 #define TB_GETDISABLEDIMAGELIST (WM_USER + 55)
56 #define TB_SETPADDING (WM_USER + 87)
58 #define MSWINDOWS_BUTTON_SHADOW_THICKNESS 2
59 #define MSWINDOWS_BLANK_SIZE 5
60 #define MSWINDOWS_MINIMUM_TOOLBAR_SIZE 8
63 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos);
65 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
70 (frame)->top_toolbar_was_visible = flag; \
72 case BOTTOM_TOOLBAR: \
73 (frame)->bottom_toolbar_was_visible = flag; \
76 (frame)->left_toolbar_was_visible = flag; \
79 (frame)->right_toolbar_was_visible = flag; \
87 allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button,
90 /* hmm what do we generate an id based on */
91 int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
92 while (!NILP (Fgethash (make_int (id),
93 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil)))
95 id = TOOLBAR_ITEM_ID_BITS (id + 1);
101 mswindows_clear_toolbar (struct frame *f, enum toolbar_pos pos,
102 int thickness_change)
104 HIMAGELIST ilist=NULL;
106 HWND toolbarwnd = TOOLBAR_HANDLE(f, pos);
111 /* Delete the buttons and remove the command from the hash table*/
112 i = SendMessage (toolbarwnd, TB_BUTTONCOUNT, 0, 0);
113 for (i--; i >= 0; i--)
115 SendMessage (toolbarwnd, TB_GETBUTTON, (WPARAM)i,
117 Fremhash(make_int(info.idCommand),
118 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE(f));
119 SendMessage (toolbarwnd, TB_DELETEBUTTON, (WPARAM)i, 0);
122 /* finally get rid of the image list assuming it clears up its
124 SendMessage (toolbarwnd, TB_GETIMAGELIST, 0, (LONG) &ilist);
127 ImageList_Destroy(ilist);
129 SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, (LPARAM)NULL);
131 ShowWindow(toolbarwnd, SW_HIDE);
134 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=0;
135 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
139 mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos)
141 int x, y, bar_width, bar_height, vert;
142 int width=-1, height=-1, bmwidth=0, bmheight=0, maxbmwidth, maxbmheight;
144 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
145 Lisp_Object button, glyph, instance;
146 Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
149 int shadow_thickness = 2; /* get this from somewhere else? */
150 int window_frame_width = 3;
151 int padding = (border_width + shadow_thickness) * 2;
152 unsigned int checksum=0;
153 struct window *w = XWINDOW (window);
154 TBBUTTON* button_tbl, *tbbutton;
155 HIMAGELIST ilist=NULL;
156 HWND toolbarwnd=NULL;
158 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
160 /* ediff bogusly sets the height to 2 for some obscure X-specific
161 reason. This ensures that we only try and output a toolbar for
163 if (bar_width < MSWINDOWS_MINIMUM_TOOLBAR_SIZE
165 bar_height < MSWINDOWS_MINIMUM_TOOLBAR_SIZE)
173 toolbarwnd = TOOLBAR_HANDLE (f,pos);
175 /* set button sizes based on bar size */
180 width = height = bar_width
181 - (window_frame_width + shadow_thickness) * 2;
184 width = height = bar_width;
186 maxbmwidth = maxbmheight = width - padding;
192 height = width = bar_height
193 - (window_frame_width + shadow_thickness) * 2;
196 width = height = bar_height;
198 maxbmwidth = maxbmheight = width - padding;
201 button = FRAME_TOOLBAR_BUTTONS (f, pos);
203 /* First loop over all of the buttons to determine how many there
204 are. This loop will also make sure that all instances are
205 instantiated so when we actually output them they will come up
207 while (!NILP (button))
210 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
211 checksum = HASH5 (checksum,
212 internal_hash (get_toolbar_button_glyph(w, tb), 0),
213 internal_hash (tb->callback, 0),
215 LISP_HASH (w->toolbar_buttons_captioned_p));
220 /* only rebuild if something has changed */
221 if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
223 /* remove the old one */
224 mswindows_clear_toolbar (f, pos, 0);
226 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=checksum;
228 /* build up the data required by win32 fns. */
229 button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
230 button = FRAME_TOOLBAR_BUTTONS (f, pos);
231 tbbutton = button_tbl;
233 while (!NILP (button))
235 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
236 HBITMAP bitmap=NULL, mask=NULL;
240 tbbutton->fsStyle = TBSTYLE_SEP;
243 tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
244 /* currently we output the toolbar again with disabled
245 buttons it might be good to use the ms disabled code
246 instead but that means another image list, so we'll stick
247 with the emacs model. */
248 tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED :
249 TBSTATE_INDETERMINATE;
250 tbbutton->fsStyle = TBSTYLE_BUTTON;
254 /* mess with the button image */
255 glyph = get_toolbar_button_glyph (w, tb);
258 instance = glyph_image_instance (glyph, window,
263 if (IMAGE_INSTANCEP (instance))
265 struct Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
267 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
269 /* we are going to honor the toolbar settings
270 and resize the bitmaps accordingly if they are
271 too big. If they are too small we leave them
272 and pad the difference - unless a different size
273 crops up in the middle, at which point we *have*
274 to resize since the ImageList won't cope.*/
278 IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth)
282 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
284 IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth
286 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight)
289 bmheight = min (maxbmheight,
290 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
292 bmwidth = min (maxbmwidth,
293 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
295 if (! (bitmap = mswindows_create_resized_bitmap
296 (p, f, bmwidth, bmheight)))
299 if (ilist) ImageList_Destroy (ilist);
300 signal_simple_error ("Couldn't resize pixmap",
303 /* we don't care if the mask fails */
304 mask = mswindows_create_resized_mask
305 (p, f, bmwidth, bmheight);
310 bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
312 bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
315 /* need to build an image list for the bitmaps */
316 if (!ilist && !(ilist = ImageList_Create
318 (IMAGE_INSTANCE_MSWINDOWS_MASK (p)
319 ? ILC_MASK : 0) | ILC_COLOR24,
320 nbuttons, nbuttons * 2 )))
323 signal_simple_error ("Couldn't create image list",
327 /* make the mask actually do something */
328 ImageList_SetBkColor (ilist, CLR_NONE);
329 /* add a bitmap to the list */
330 if ((tbbutton->iBitmap =
334 : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
336 : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
339 if (ilist) ImageList_Destroy (ilist);
341 ("couldn't add image to image list", instance);
343 /* we're done with these now */
344 DeleteObject (bitmap);
349 Fputhash (make_int (tbbutton->idCommand),
350 button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
353 /* now fix up the button size */
357 tb->border_width = border_width;
358 tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
359 tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
364 tb->height = MSWINDOWS_BLANK_SIZE;
366 tb->width = MSWINDOWS_BLANK_SIZE;
373 /* move on to the next button */
378 button = FRAME_TOOLBAR_BUTTONS (f, pos);
380 /* create the toolbar window? */
384 CreateWindowEx ( WS_EX_WINDOWEDGE,
387 WS_CHILD | WS_VISIBLE
388 | (style_3d ? WS_DLGFRAME : 0)
389 | TBSTYLE_TOOLTIPS | CCS_NORESIZE
390 | CCS_NOPARENTALIGN | CCS_NODIVIDER,
391 x, y, bar_width, bar_height,
392 FRAME_MSWINDOWS_HANDLE (f),
393 (HMENU)(TOOLBAR_ID_BIAS + pos),
398 ImageList_Destroy (ilist);
399 error ("couldn't create toolbar");
402 /* finally populate with images */
403 if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
404 (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1)
406 mswindows_clear_toolbar (f, pos, 0);
407 error ("couldn't set button structure size");
411 height = min (bmheight + padding, height);
413 width = min (bmwidth + padding, width);
415 /* pad the buttons */
416 SendMessage (toolbarwnd, TB_SETPADDING,
417 0, MAKELPARAM(width - bmwidth, height - bmheight));
419 /* set the size of buttons */
420 SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0,
421 (LPARAM)MAKELONG (width, height));
423 /* set the size of bitmaps */
424 SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0,
425 (LPARAM)MAKELONG (bmwidth, bmheight));
427 /* tell it we've done it */
428 SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0);
430 /* finally populate with images */
431 if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
432 (WPARAM)nbuttons, (LPARAM)button_tbl))
434 mswindows_clear_toolbar (f, pos, 0);
435 error ("couldn't add button list to toolbar");
438 /* vertical toolbars need more rows */
442 SendMessage (toolbarwnd, TB_SETROWS,
443 MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp);
449 SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE),
453 /* finally populate with images */
454 if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
457 SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0,
460 mswindows_clear_toolbar (f, pos, 0);
461 error ("couldn't add image list to toolbar");
464 /* now display the window */
465 ShowWindow (toolbarwnd, SW_SHOW);
466 /* no idea why this is necessary but initial display will not
468 mswindows_move_toolbar (f, pos);
470 if (button_tbl) xfree (button_tbl);
472 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
477 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos)
479 int bar_x, bar_y, bar_width, bar_height, vert;
480 HWND toolbarwnd = TOOLBAR_HANDLE(f,pos);
484 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
487 /* #### This terrible mangling with coordinates perhaps
488 arises from different treatment of toolbar positions
489 by Windows and by XEmacs. */
494 bar_width+=3; bar_height+=3;
498 bar_height++; bar_width++;
502 bar_width+=4; bar_height+=4;
506 bar_width++; bar_height++;
509 SetWindowPos (toolbarwnd, NULL, bar_x, bar_y,
510 bar_width, bar_height, SWP_NOZORDER);
515 mswindows_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
518 assert (FRAME_MSWINDOWS_P (f));
520 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
521 mswindows_move_toolbar (f, TOP_TOOLBAR);
523 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
524 mswindows_move_toolbar (f, BOTTOM_TOOLBAR);
526 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
527 mswindows_move_toolbar (f, LEFT_TOOLBAR);
529 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
530 mswindows_move_toolbar (f, RIGHT_TOOLBAR);
534 mswindows_redraw_frame_toolbars (struct frame *f)
536 mswindows_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
537 FRAME_PIXHEIGHT (f));
541 mswindows_initialize_frame_toolbars (struct frame *f)
547 mswindows_output_frame_toolbars (struct frame *f)
549 assert (FRAME_MSWINDOWS_P (f));
551 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
552 mswindows_output_toolbar (f, TOP_TOOLBAR);
553 else if (f->top_toolbar_was_visible)
554 mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
556 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
557 mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
558 else if (f->bottom_toolbar_was_visible)
559 mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
561 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
562 mswindows_output_toolbar (f, LEFT_TOOLBAR);
563 else if (f->left_toolbar_was_visible)
564 mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
566 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
567 mswindows_output_toolbar (f, RIGHT_TOOLBAR);
568 else if (f->right_toolbar_was_visible)
569 mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
573 mswindows_free_frame_toolbars (struct frame *f)
576 #define DELETE_TOOLBAR(pos) \
577 mswindows_clear_toolbar(f, 0, pos); \
578 if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + pos))) \
581 DELETE_TOOLBAR(TOP_TOOLBAR);
582 DELETE_TOOLBAR(BOTTOM_TOOLBAR);
583 DELETE_TOOLBAR(LEFT_TOOLBAR);
584 DELETE_TOOLBAR(RIGHT_TOOLBAR);
585 #undef DELETE_TOOLBAR
588 /* map toolbar hwnd to pos*/
589 int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
591 int id = GetDlgCtrlID(ctrl);
592 return id ? id - TOOLBAR_ID_BIAS : -1;
596 mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
598 Lisp_Object button = Fgethash (make_int (command_id),
599 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
603 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
604 return tb->help_string;
610 * Return value is Qt if we have dispatched the command,
611 * or Qnil if id has not been mapped to a callback.
612 * Window procedure may try other targets to route the
613 * command if we return nil
616 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
618 /* Try to map the command id through the proper hash table */
619 Lisp_Object button, data, fn, arg, frame;
621 button = Fgethash (make_int (id),
622 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
627 data = XTOOLBAR_BUTTON (button)->callback;
633 /* Ok, this is our one. Enqueue it. */
634 get_gui_callback (data, &fn, &arg);
635 XSETFRAME (frame, f);
636 mswindows_enqueue_misc_user_event (frame, fn, arg);
641 /************************************************************************/
643 /************************************************************************/
646 console_type_create_toolbar_mswindows (void)
648 CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
649 CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
650 CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
651 CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);
652 CONSOLE_HAS_METHOD (mswindows, redraw_frame_toolbars);