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 = HASH4 (checksum,
209 internal_hash (get_toolbar_button_glyph(w, tb), 0),
210 internal_hash (tb->callback, 0),
216 /* only rebuild if something has changed */
217 if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
219 /* remove the old one */
220 mswindows_clear_toolbar (f, pos, 0);
222 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)=checksum;
224 /* build up the data required by win32 fns. */
225 button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
226 button = FRAME_TOOLBAR_BUTTONS (f, pos);
227 tbbutton = button_tbl;
229 while (!NILP (button))
231 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
232 HBITMAP bitmap=NULL, mask=NULL;
236 tbbutton->fsStyle = TBSTYLE_SEP;
239 tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
240 /* currently we output the toolbar again with disabled
241 buttons it might be good to use the ms disabled code
242 instead but that means another image list, so we'll stick
243 with the emacs model. */
244 tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED :
245 TBSTATE_INDETERMINATE;
246 tbbutton->fsStyle = TBSTYLE_BUTTON;
250 /* mess with the button image */
251 glyph = get_toolbar_button_glyph (w, tb);
254 instance = glyph_image_instance (glyph, window,
259 if (IMAGE_INSTANCEP (instance))
261 struct Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
263 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
265 /* we are going to honor the toolbar settings
266 and resize the bitmaps accordingly if they are
267 too big. If they are too small we leave them
268 and pad the difference - unless a different size
269 crops up in the middle, at which point we *have*
270 to resize since the ImageList won't cope.*/
274 IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth)
278 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
280 IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth
282 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight)
285 bmheight = min (maxbmheight,
286 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
288 bmwidth = min (maxbmwidth,
289 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
291 if (! (bitmap = mswindows_create_resized_bitmap
292 (p, f, bmwidth, bmheight)))
295 if (ilist) ImageList_Destroy (ilist);
296 signal_simple_error ("Couldn't resize pixmap",
299 /* we don't care if the mask fails */
300 mask = mswindows_create_resized_mask
301 (p, f, bmwidth, bmheight);
306 bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
308 bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
311 /* need to build an image list for the bitmaps */
312 if (!ilist && !(ilist = ImageList_Create
314 (IMAGE_INSTANCE_MSWINDOWS_MASK (p)
315 ? ILC_MASK : 0) | ILC_COLOR24,
316 nbuttons, nbuttons * 2 )))
319 signal_simple_error ("Couldn't create image list",
323 /* make the mask actually do something */
324 ImageList_SetBkColor (ilist, CLR_NONE);
325 /* add a bitmap to the list */
326 if ((tbbutton->iBitmap =
330 : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
332 : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
335 if (ilist) ImageList_Destroy (ilist);
337 ("couldn't add image to image list", instance);
339 /* we're done with these now */
340 DeleteObject (bitmap);
345 Fputhash (make_int (tbbutton->idCommand),
346 button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
349 /* now fix up the button size */
353 tb->border_width = border_width;
354 tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
355 tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
360 tb->height = MSWINDOWS_BLANK_SIZE;
362 tb->width = MSWINDOWS_BLANK_SIZE;
369 /* move on to the next button */
374 button = FRAME_TOOLBAR_BUTTONS (f, pos);
376 /* create the toolbar window? */
380 CreateWindowEx ( WS_EX_WINDOWEDGE,
383 WS_CHILD | WS_VISIBLE
384 | (style_3d ? WS_DLGFRAME : 0)
385 | TBSTYLE_TOOLTIPS | CCS_NORESIZE
386 | CCS_NOPARENTALIGN | CCS_NODIVIDER,
387 x, y, bar_width, bar_height,
388 FRAME_MSWINDOWS_HANDLE (f),
389 (HMENU)(TOOLBAR_ID_BIAS + pos),
394 ImageList_Destroy (ilist);
395 error ("couldn't create toolbar");
398 /* finally populate with images */
399 if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
400 (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1)
402 mswindows_clear_toolbar (f, pos, 0);
403 error ("couldn't set button structure size");
407 height = min (bmheight + padding, height);
409 width = min (bmwidth + padding, width);
411 /* pad the buttons */
412 SendMessage (toolbarwnd, TB_SETPADDING,
413 0, MAKELPARAM(width - bmwidth, height - bmheight));
415 /* set the size of buttons */
416 SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0,
417 (LPARAM)MAKELONG (width, height));
419 /* set the size of bitmaps */
420 SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0,
421 (LPARAM)MAKELONG (bmwidth, bmheight));
423 /* tell it we've done it */
424 SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0);
426 /* finally populate with images */
427 if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
428 (WPARAM)nbuttons, (LPARAM)button_tbl))
430 mswindows_clear_toolbar (f, pos, 0);
431 error ("couldn't add button list to toolbar");
434 /* vertical toolbars need more rows */
438 SendMessage (toolbarwnd, TB_SETROWS,
439 MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp);
445 SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE),
449 /* finally populate with images */
450 if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
453 SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0,
456 mswindows_clear_toolbar (f, pos, 0);
457 error ("couldn't add image list to toolbar");
460 /* now display the window */
461 ShowWindow (toolbarwnd, SW_SHOW);
463 if (button_tbl) xfree (button_tbl);
465 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
470 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos)
472 int bar_x, bar_y, bar_width, bar_height, vert;
473 HWND toolbarwnd = TOOLBAR_HANDLE(f,pos);
477 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
480 /* #### This terrible mangling with coordinates perhaps
481 arises from different treatment of toolbar positions
482 by Windows and by XEmacs. */
487 bar_width+=3; bar_height+=3;
491 bar_height++; bar_width++;
495 bar_width+=4; bar_height+=4;
499 bar_width++; bar_height++;
502 SetWindowPos (toolbarwnd, NULL, bar_x, bar_y,
503 bar_width, bar_height, SWP_NOZORDER);
508 mswindows_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
511 assert (FRAME_MSWINDOWS_P (f));
513 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
514 mswindows_move_toolbar (f, TOP_TOOLBAR);
516 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
517 mswindows_move_toolbar (f, BOTTOM_TOOLBAR);
519 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
520 mswindows_move_toolbar (f, LEFT_TOOLBAR);
522 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
523 mswindows_move_toolbar (f, RIGHT_TOOLBAR);
527 mswindows_initialize_frame_toolbars (struct frame *f)
533 mswindows_output_frame_toolbars (struct frame *f)
535 assert (FRAME_MSWINDOWS_P (f));
537 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
538 mswindows_output_toolbar (f, TOP_TOOLBAR);
539 else if (f->top_toolbar_was_visible)
540 mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
542 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
543 mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
544 else if (f->bottom_toolbar_was_visible)
545 mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
547 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
548 mswindows_output_toolbar (f, LEFT_TOOLBAR);
549 else if (f->left_toolbar_was_visible)
550 mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
552 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
553 mswindows_output_toolbar (f, RIGHT_TOOLBAR);
554 else if (f->right_toolbar_was_visible)
555 mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
559 mswindows_free_frame_toolbars (struct frame *f)
562 #define DELETE_TOOLBAR(pos) \
563 mswindows_clear_toolbar(f, 0, pos); \
564 if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), TOOLBAR_ID_BIAS + pos))) \
567 DELETE_TOOLBAR(TOP_TOOLBAR);
568 DELETE_TOOLBAR(BOTTOM_TOOLBAR);
569 DELETE_TOOLBAR(LEFT_TOOLBAR);
570 DELETE_TOOLBAR(RIGHT_TOOLBAR);
571 #undef DELETE_TOOLBAR
574 /* map toolbar hwnd to pos*/
575 int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
577 int id = GetDlgCtrlID(ctrl);
578 return id ? id - TOOLBAR_ID_BIAS : -1;
582 mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
584 Lisp_Object button = Fgethash (make_int (command_id),
585 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
589 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
590 return tb->help_string;
596 * Return value is Qt if we have dispatched the command,
597 * or Qnil if id has not been mapped to a callback.
598 * Window procedure may try other targets to route the
599 * command if we return nil
602 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
604 /* Try to map the command id through the proper hash table */
605 Lisp_Object button, data, fn, arg, frame;
607 button = Fgethash (make_int (id),
608 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
613 data = XTOOLBAR_BUTTON (button)->callback;
619 /* Ok, this is our one. Enqueue it. */
620 get_gui_callback (data, &fn, &arg);
621 XSETFRAME (frame, f);
622 mswindows_enqueue_misc_user_event (frame, fn, arg);
627 /************************************************************************/
629 /************************************************************************/
632 console_type_create_toolbar_mswindows (void)
634 CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
635 CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
636 CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
637 CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);