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)
59 #define TBSTYLE_FLAT 0x800
61 #define MSWINDOWS_BUTTON_SHADOW_THICKNESS 2
62 #define MSWINDOWS_BLANK_SIZE 5
63 #define MSWINDOWS_MINIMUM_TOOLBAR_SIZE 8
66 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos);
68 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
73 (frame)->top_toolbar_was_visible = flag; \
75 case BOTTOM_TOOLBAR: \
76 (frame)->bottom_toolbar_was_visible = flag; \
79 (frame)->left_toolbar_was_visible = flag; \
82 (frame)->right_toolbar_was_visible = flag; \
90 allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button,
93 /* hmm what do we generate an id based on */
94 int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
95 while (!NILP (Fgethash (make_int (id),
96 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil)))
98 id = TOOLBAR_ITEM_ID_BITS (id + 1);
104 mswindows_clear_toolbar (struct frame *f, enum toolbar_pos pos,
105 int thickness_change)
107 HIMAGELIST ilist=NULL;
109 HWND toolbarwnd = TOOLBAR_HANDLE(f, pos);
114 /* Delete the buttons and remove the command from the hash table*/
115 i = SendMessage (toolbarwnd, TB_BUTTONCOUNT, 0, 0);
116 for (i--; i >= 0; i--)
118 SendMessage (toolbarwnd, TB_GETBUTTON, (WPARAM)i,
120 Fremhash(make_int(info.idCommand),
121 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE(f));
122 SendMessage (toolbarwnd, TB_DELETEBUTTON, (WPARAM)i, 0);
125 /* finally get rid of the image list assuming it clears up its
127 SendMessage (toolbarwnd, TB_GETIMAGELIST, 0, (LONG) &ilist);
130 ImageList_Destroy(ilist);
132 SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, (LPARAM)NULL);
134 ShowWindow(toolbarwnd, SW_HIDE);
137 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM (f, pos) = 0;
138 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
142 mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos)
144 int x, y, bar_width, bar_height, vert;
145 int width=-1, height=-1, bmwidth=0, bmheight=0, maxbmwidth, maxbmheight;
147 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
148 Lisp_Object button, glyph, instance;
149 Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
152 int shadow_thickness = 2; /* get this from somewhere else? */
153 int window_frame_width = 3;
154 int padding = (border_width + shadow_thickness) * 2;
155 unsigned int checksum=0;
156 struct window *w = XWINDOW (window);
157 TBBUTTON* button_tbl, *tbbutton;
158 HIMAGELIST ilist=NULL;
159 HWND toolbarwnd=NULL;
161 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
163 /* ediff bogusly sets the height to 2 for some obscure X-specific
164 reason. This ensures that we only try and output a toolbar for
166 if (bar_width < MSWINDOWS_MINIMUM_TOOLBAR_SIZE
168 bar_height < MSWINDOWS_MINIMUM_TOOLBAR_SIZE)
176 toolbarwnd = TOOLBAR_HANDLE (f,pos);
178 /* set button sizes based on bar size */
183 width = height = bar_width
184 - (window_frame_width + shadow_thickness) * 2;
187 width = height = bar_width;
189 maxbmwidth = maxbmheight = width - padding;
195 height = width = bar_height
196 - (window_frame_width + shadow_thickness) * 2;
199 width = height = bar_height;
201 maxbmwidth = maxbmheight = width - padding;
204 button = FRAME_TOOLBAR_BUTTONS (f, pos);
206 /* First loop over all of the buttons to determine how many there
207 are. This loop will also make sure that all instances are
208 instantiated so when we actually output them they will come up
210 while (!NILP (button))
213 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
214 checksum = HASH5 (checksum,
215 internal_hash (get_toolbar_button_glyph(w, tb), 0),
216 internal_hash (tb->callback, 0),
218 LISP_HASH (w->toolbar_buttons_captioned_p));
223 /* only rebuild if something has changed */
224 if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
226 /* remove the old one */
227 mswindows_clear_toolbar (f, pos, 0);
229 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM (f, pos)=checksum;
231 /* build up the data required by win32 fns. */
232 button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
233 button = FRAME_TOOLBAR_BUTTONS (f, pos);
234 tbbutton = button_tbl;
236 while (!NILP (button))
238 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
239 HBITMAP bitmap=NULL, mask=NULL;
243 tbbutton->fsStyle = TBSTYLE_SEP;
246 tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
247 /* currently we output the toolbar again with disabled
248 buttons it might be good to use the ms disabled code
249 instead but that means another image list, so we'll stick
250 with the emacs model. */
251 tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED :
252 TBSTATE_INDETERMINATE;
253 tbbutton->fsStyle = TBSTYLE_BUTTON;
257 /* mess with the button image */
258 glyph = get_toolbar_button_glyph (w, tb);
261 instance = glyph_image_instance (glyph, window,
266 if (IMAGE_INSTANCEP (instance))
268 Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
270 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
272 /* we are going to honor the toolbar settings
273 and resize the bitmaps accordingly if they are
274 too big. If they are too small we leave them
275 and pad the difference - unless a different size
276 crops up in the middle, at which point we *have*
277 to resize since the ImageList won't cope.*/
281 IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth)
285 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
287 IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth
289 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight)
292 bmheight = min (maxbmheight,
293 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
295 bmwidth = min (maxbmwidth,
296 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
298 if (! (bitmap = mswindows_create_resized_bitmap
299 (p, f, bmwidth, bmheight)))
302 if (ilist) ImageList_Destroy (ilist);
303 signal_simple_error ("Couldn't resize pixmap",
306 /* we don't care if the mask fails */
307 mask = mswindows_create_resized_mask
308 (p, f, bmwidth, bmheight);
313 bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
315 bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
318 /* need to build an image list for the bitmaps */
319 if (!ilist && !(ilist = ImageList_Create
321 (IMAGE_INSTANCE_MSWINDOWS_MASK (p)
322 ? ILC_MASK : 0) | ILC_COLOR24,
323 nbuttons, nbuttons * 2 )))
326 signal_simple_error ("Couldn't create image list",
330 /* make the mask actually do something */
331 ImageList_SetBkColor (ilist, CLR_NONE);
332 /* add a bitmap to the list */
333 if ((tbbutton->iBitmap =
337 : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
339 : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
342 if (ilist) ImageList_Destroy (ilist);
344 ("couldn't add image to image list", instance);
346 /* we're done with these now */
347 DeleteObject (bitmap);
352 Fputhash (make_int (tbbutton->idCommand),
353 button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
356 /* now fix up the button size */
360 tb->border_width = border_width;
361 tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
362 tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
367 tb->height = MSWINDOWS_BLANK_SIZE;
369 tb->width = MSWINDOWS_BLANK_SIZE;
376 /* move on to the next button */
381 button = FRAME_TOOLBAR_BUTTONS (f, pos);
383 /* create the toolbar window? */
387 CreateWindowEx ( WS_EX_WINDOWEDGE,
391 | (style_3d ? WS_DLGFRAME : 0)
394 | CCS_NOPARENTALIGN | CCS_NODIVIDER
396 x, y, bar_width, bar_height,
397 FRAME_MSWINDOWS_HANDLE (f),
398 (HMENU)(TOOLBAR_ID_BIAS + pos),
403 ImageList_Destroy (ilist);
404 error ("couldn't create toolbar");
407 /* finally populate with images */
408 if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
409 (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1)
411 mswindows_clear_toolbar (f, pos, 0);
412 error ("couldn't set button structure size");
416 height = min (bmheight + padding, height);
418 width = min (bmwidth + padding, width);
420 /* pad the buttons */
421 SendMessage (toolbarwnd, TB_SETPADDING,
422 0, MAKELPARAM(width - bmwidth, height - bmheight));
424 /* set the size of buttons */
425 SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0,
426 (LPARAM)MAKELONG (width, height));
428 /* set the size of bitmaps */
429 SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0,
430 (LPARAM)MAKELONG (bmwidth, bmheight));
432 /* tell it we've done it */
433 SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0);
435 /* finally populate with images */
436 if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
437 (WPARAM)nbuttons, (LPARAM)button_tbl))
439 mswindows_clear_toolbar (f, pos, 0);
440 error ("couldn't add button list to toolbar");
443 /* vertical toolbars need more rows */
447 SendMessage (toolbarwnd, TB_SETROWS,
448 MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp);
454 SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE),
458 /* finally populate with images */
459 if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
462 SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0,
465 mswindows_clear_toolbar (f, pos, 0);
466 error ("couldn't add image list to toolbar");
469 /* now display the window */
470 ShowWindow (toolbarwnd, SW_SHOW);
471 /* no idea why this is necessary but initial display will not
473 mswindows_move_toolbar (f, pos);
475 if (button_tbl) xfree (button_tbl);
477 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
482 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos)
484 int bar_x, bar_y, bar_width, bar_height, vert;
485 HWND toolbarwnd = TOOLBAR_HANDLE(f,pos);
489 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
492 /* #### This terrible mangling with coordinates perhaps
493 arises from different treatment of toolbar positions
494 by Windows and by XEmacs. */
499 bar_width+=3; bar_height+=3;
503 bar_height++; bar_width++;
507 bar_width+=4; bar_height+=4;
511 bar_width++; bar_height++;
514 SetWindowPos (toolbarwnd, NULL, bar_x, bar_y,
515 bar_width, bar_height, SWP_NOZORDER);
520 mswindows_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
523 assert (FRAME_MSWINDOWS_P (f));
525 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
526 mswindows_move_toolbar (f, TOP_TOOLBAR);
528 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
529 mswindows_move_toolbar (f, BOTTOM_TOOLBAR);
531 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
532 mswindows_move_toolbar (f, LEFT_TOOLBAR);
534 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
535 mswindows_move_toolbar (f, RIGHT_TOOLBAR);
539 mswindows_redraw_frame_toolbars (struct frame *f)
541 mswindows_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
542 FRAME_PIXHEIGHT (f));
546 mswindows_initialize_frame_toolbars (struct frame *f)
552 mswindows_output_frame_toolbars (struct frame *f)
554 assert (FRAME_MSWINDOWS_P (f));
556 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
557 mswindows_output_toolbar (f, TOP_TOOLBAR);
558 else if (f->top_toolbar_was_visible)
559 mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
561 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
562 mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
563 else if (f->bottom_toolbar_was_visible)
564 mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
566 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
567 mswindows_output_toolbar (f, LEFT_TOOLBAR);
568 else if (f->left_toolbar_was_visible)
569 mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
571 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
572 mswindows_output_toolbar (f, RIGHT_TOOLBAR);
573 else if (f->right_toolbar_was_visible)
574 mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
578 mswindows_free_frame_toolbars (struct frame *f)
581 #define DELETE_TOOLBAR(pos) \
582 mswindows_clear_toolbar(f, pos, 0); \
583 if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), \
584 TOOLBAR_ID_BIAS + pos))) \
587 DELETE_TOOLBAR(TOP_TOOLBAR);
588 DELETE_TOOLBAR(BOTTOM_TOOLBAR);
589 DELETE_TOOLBAR(LEFT_TOOLBAR);
590 DELETE_TOOLBAR(RIGHT_TOOLBAR);
591 #undef DELETE_TOOLBAR
594 /* map toolbar hwnd to pos*/
595 static int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
597 int id = GetDlgCtrlID(ctrl);
598 return id ? id - TOOLBAR_ID_BIAS : -1;
602 mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
604 Lisp_Object button = Fgethash (make_int (command_id),
605 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
609 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
610 return tb->help_string;
616 * Return value is Qt if we have dispatched the command,
617 * or Qnil if id has not been mapped to a callback.
618 * Window procedure may try other targets to route the
619 * command if we return nil
622 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
624 /* Try to map the command id through the proper hash table */
625 Lisp_Object button, data, fn, arg, frame;
627 button = Fgethash (make_int (id),
628 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
633 data = XTOOLBAR_BUTTON (button)->callback;
639 /* Ok, this is our one. Enqueue it. */
640 get_gui_callback (data, &fn, &arg);
641 XSETFRAME (frame, f);
642 mswindows_enqueue_misc_user_event (frame, fn, arg);
647 /************************************************************************/
649 /************************************************************************/
652 console_type_create_toolbar_mswindows (void)
654 CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
655 CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
656 CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
657 CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);
658 CONSOLE_HAS_METHOD (mswindows, redraw_frame_toolbars);