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
62 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
67 (frame)->top_toolbar_was_visible = flag; \
69 case BOTTOM_TOOLBAR: \
70 (frame)->bottom_toolbar_was_visible = flag; \
73 (frame)->left_toolbar_was_visible = flag; \
76 (frame)->right_toolbar_was_visible = flag; \
84 allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button,
87 /* hmm what do we generate an id based on */
88 int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
89 while (!NILP (Fgethash (make_int (id),
90 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil)))
92 id = TOOLBAR_ITEM_ID_BITS (id + 1);
98 mswindows_clear_toolbar (struct frame *f, enum toolbar_pos pos,
101 HIMAGELIST ilist=NULL;
103 HWND toolbarwnd = TOOLBAR_HANDLE(f, pos);
108 /* Delete the buttons and remove the command from the hash table*/
109 i = SendMessage (toolbarwnd, TB_BUTTONCOUNT, 0, 0);
110 for (i--; i >= 0; i--)
112 SendMessage (toolbarwnd, TB_GETBUTTON, (WPARAM)i,
114 Fremhash(make_int(info.idCommand),
115 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE(f));
116 SendMessage (toolbarwnd, TB_DELETEBUTTON, (WPARAM)i, 0);
119 /* finally get rid of the image list assuming it clears up its
121 SendMessage (toolbarwnd, TB_GETIMAGELIST, 0, (LONG) &ilist);
124 ImageList_Destroy(ilist);
126 SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, (LPARAM)NULL);
128 ShowWindow(toolbarwnd, SW_HIDE);
131 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=0;
132 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
136 mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos)
138 int x, y, bar_width, bar_height, vert;
139 int width=-1, height=-1, bmwidth=0, bmheight=0, maxbmwidth, maxbmheight;
141 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
142 Lisp_Object button, glyph, instance;
143 Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
146 int shadow_thickness = 2; /* get this from somewhere else? */
147 int window_frame_width = 3;
148 int padding = (border_width + shadow_thickness) * 2;
149 unsigned int checksum=0;
150 struct window *w = XWINDOW (window);
151 TBBUTTON* button_tbl, *tbbutton;
152 HIMAGELIST ilist=NULL;
153 HWND toolbarwnd=NULL;
155 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
157 /* ediff bogusly sets the height to 2 for some obscure X-specific
158 reason. This ensures that we only try and output a toolbar for
160 if (bar_width < MSWINDOWS_MINIMUM_TOOLBAR_SIZE
162 bar_height < MSWINDOWS_MINIMUM_TOOLBAR_SIZE)
170 toolbarwnd = TOOLBAR_HANDLE (f,pos);
172 /* set button sizes based on bar size */
177 width = height = bar_width
178 - (window_frame_width + shadow_thickness) * 2;
181 width = height = bar_width;
183 maxbmwidth = maxbmheight = width - padding;
189 height = width = bar_height
190 - (window_frame_width + shadow_thickness) * 2;
193 width = height = bar_height;
195 maxbmwidth = maxbmheight = width - padding;
198 button = FRAME_TOOLBAR_BUTTONS (f, pos);
200 /* First loop over all of the buttons to determine how many there
201 are. This loop will also make sure that all instances are
202 instantiated so when we actually output them they will come up
204 while (!NILP (button))
207 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
208 checksum = HASH5 (checksum,
209 internal_hash (get_toolbar_button_glyph(w, tb), 0),
210 internal_hash (tb->callback, 0),
212 LISP_HASH (w->toolbar_buttons_captioned_p));
217 /* only rebuild if something has changed */
218 if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
220 /* remove the old one */
221 mswindows_clear_toolbar (f, pos, 0);
223 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=checksum;
225 /* build up the data required by win32 fns. */
226 button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
227 button = FRAME_TOOLBAR_BUTTONS (f, pos);
228 tbbutton = button_tbl;
230 while (!NILP (button))
232 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
233 HBITMAP bitmap=NULL, mask=NULL;
237 tbbutton->fsStyle = TBSTYLE_SEP;
240 tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
241 /* currently we output the toolbar again with disabled
242 buttons it might be good to use the ms disabled code
243 instead but that means another image list, so we'll stick
244 with the emacs model. */
245 tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED :
246 TBSTATE_INDETERMINATE;
247 tbbutton->fsStyle = TBSTYLE_BUTTON;
251 /* mess with the button image */
252 glyph = get_toolbar_button_glyph (w, tb);
255 instance = glyph_image_instance (glyph, window,
260 if (IMAGE_INSTANCEP (instance))
262 struct Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
264 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
266 /* we are going to honor the toolbar settings
267 and resize the bitmaps accordingly if they are
268 too big. If they are too small we leave them
269 and pad the difference - unless a different size
270 crops up in the middle, at which point we *have*
271 to resize since the ImageList won't cope.*/
275 IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth)
279 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
281 IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth
283 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight)
286 bmheight = min (maxbmheight,
287 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
289 bmwidth = min (maxbmwidth,
290 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
292 if (! (bitmap = mswindows_create_resized_bitmap
293 (p, f, bmwidth, bmheight)))
296 if (ilist) ImageList_Destroy (ilist);
297 signal_simple_error ("Couldn't resize pixmap",
300 /* we don't care if the mask fails */
301 mask = mswindows_create_resized_mask
302 (p, f, bmwidth, bmheight);
307 bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
309 bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
312 /* need to build an image list for the bitmaps */
313 if (!ilist && !(ilist = ImageList_Create
315 (IMAGE_INSTANCE_MSWINDOWS_MASK (p)
316 ? ILC_MASK : 0) | ILC_COLOR24,
317 nbuttons, nbuttons * 2 )))
320 signal_simple_error ("Couldn't create image list",
324 /* make the mask actually do something */
325 ImageList_SetBkColor (ilist, CLR_NONE);
326 /* add a bitmap to the list */
327 if ((tbbutton->iBitmap =
331 : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
333 : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
336 if (ilist) ImageList_Destroy (ilist);
338 ("couldn't add image to image list", instance);
340 /* we're done with these now */
341 DeleteObject (bitmap);
346 Fputhash (make_int (tbbutton->idCommand),
347 button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
350 /* now fix up the button size */
354 tb->border_width = border_width;
355 tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
356 tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
361 tb->height = MSWINDOWS_BLANK_SIZE;
363 tb->width = MSWINDOWS_BLANK_SIZE;
370 /* move on to the next button */
375 button = FRAME_TOOLBAR_BUTTONS (f, pos);
377 /* create the toolbar window? */
381 CreateWindowEx ( WS_EX_WINDOWEDGE,
384 WS_CHILD | WS_VISIBLE
385 | (style_3d ? WS_DLGFRAME : 0)
386 | TBSTYLE_TOOLTIPS | CCS_NORESIZE
387 | CCS_NOPARENTALIGN | CCS_NODIVIDER,
388 x, y, bar_width, bar_height,
389 FRAME_MSWINDOWS_HANDLE (f),
390 (HMENU)(TOOLBAR_ID_BIAS + pos),
395 ImageList_Destroy (ilist);
396 error ("couldn't create toolbar");
399 /* finally populate with images */
400 if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
401 (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1)
403 mswindows_clear_toolbar (f, pos, 0);
404 error ("couldn't set button structure size");
408 height = min (bmheight + padding, height);
410 width = min (bmwidth + padding, width);
412 /* pad the buttons */
413 SendMessage (toolbarwnd, TB_SETPADDING,
414 0, MAKELPARAM(width - bmwidth, height - bmheight));
416 /* set the size of buttons */
417 SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0,
418 (LPARAM)MAKELONG (width, height));
420 /* set the size of bitmaps */
421 SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0,
422 (LPARAM)MAKELONG (bmwidth, bmheight));
424 /* tell it we've done it */
425 SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0);
427 /* finally populate with images */
428 if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
429 (WPARAM)nbuttons, (LPARAM)button_tbl))
431 mswindows_clear_toolbar (f, pos, 0);
432 error ("couldn't add button list to toolbar");
435 /* vertical toolbars need more rows */
439 SendMessage (toolbarwnd, TB_SETROWS,
440 MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp);
446 SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE),
450 /* finally populate with images */
451 if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
454 SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0,
457 mswindows_clear_toolbar (f, pos, 0);
458 error ("couldn't add image list to toolbar");
461 /* now display the window */
462 ShowWindow (toolbarwnd, SW_SHOW);
464 if (button_tbl) xfree (button_tbl);
466 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
471 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos)
473 int bar_x, bar_y, bar_width, bar_height, vert;
474 HWND toolbarwnd = TOOLBAR_HANDLE(f,pos);
478 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
481 /* #### This terrible mangling with coordinates perhaps
482 arises from different treatment of toolbar positions
483 by Windows and by XEmacs. */
488 bar_width+=3; bar_height+=3;
492 bar_height++; bar_width++;
496 bar_width+=4; bar_height+=4;
500 bar_width++; bar_height++;
503 SetWindowPos (toolbarwnd, NULL, bar_x, bar_y,
504 bar_width, bar_height, SWP_NOZORDER);
509 mswindows_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
512 assert (FRAME_MSWINDOWS_P (f));
514 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
515 mswindows_move_toolbar (f, TOP_TOOLBAR);
517 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
518 mswindows_move_toolbar (f, BOTTOM_TOOLBAR);
520 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
521 mswindows_move_toolbar (f, LEFT_TOOLBAR);
523 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
524 mswindows_move_toolbar (f, RIGHT_TOOLBAR);
528 mswindows_initialize_frame_toolbars (struct frame *f)
534 mswindows_output_frame_toolbars (struct frame *f)
536 assert (FRAME_MSWINDOWS_P (f));
538 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
539 mswindows_output_toolbar (f, TOP_TOOLBAR);
540 else if (f->top_toolbar_was_visible)
541 mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
543 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
544 mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
545 else if (f->bottom_toolbar_was_visible)
546 mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
548 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
549 mswindows_output_toolbar (f, LEFT_TOOLBAR);
550 else if (f->left_toolbar_was_visible)
551 mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
553 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
554 mswindows_output_toolbar (f, RIGHT_TOOLBAR);
555 else if (f->right_toolbar_was_visible)
556 mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
560 mswindows_free_frame_toolbars (struct frame *f)
563 #define DELETE_TOOLBAR(pos) \
564 mswindows_clear_toolbar(f, 0, pos); \
565 if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + pos))) \
568 DELETE_TOOLBAR(TOP_TOOLBAR);
569 DELETE_TOOLBAR(BOTTOM_TOOLBAR);
570 DELETE_TOOLBAR(LEFT_TOOLBAR);
571 DELETE_TOOLBAR(RIGHT_TOOLBAR);
572 #undef DELETE_TOOLBAR
575 /* map toolbar hwnd to pos*/
576 int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
578 int id = GetDlgCtrlID(ctrl);
579 return id ? id - TOOLBAR_ID_BIAS : -1;
583 mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
585 Lisp_Object button = Fgethash (make_int (command_id),
586 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
590 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
591 return tb->help_string;
597 * Return value is Qt if we have dispatched the command,
598 * or Qnil if id has not been mapped to a callback.
599 * Window procedure may try other targets to route the
600 * command if we return nil
603 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
605 /* Try to map the command id through the proper hash table */
606 Lisp_Object button, data, fn, arg, frame;
608 button = Fgethash (make_int (id),
609 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
614 data = XTOOLBAR_BUTTON (button)->callback;
620 /* Ok, this is our one. Enqueue it. */
621 get_gui_callback (data, &fn, &arg);
622 XSETFRAME (frame, f);
623 mswindows_enqueue_misc_user_event (frame, fn, arg);
628 /************************************************************************/
630 /************************************************************************/
633 console_type_create_toolbar_mswindows (void)
635 CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
636 CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
637 CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
638 CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);