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 <andy@xemacs.org>, 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)
50 #define MSWINDOWS_BUTTON_SHADOW_THICKNESS 2
51 #define MSWINDOWS_BLANK_SIZE 5
52 #define MSWINDOWS_MINIMUM_TOOLBAR_SIZE 8
55 mswindows_move_toolbar (struct frame *f, enum toolbar_pos pos);
57 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
62 (frame)->top_toolbar_was_visible = flag; \
64 case BOTTOM_TOOLBAR: \
65 (frame)->bottom_toolbar_was_visible = flag; \
68 (frame)->left_toolbar_was_visible = flag; \
71 (frame)->right_toolbar_was_visible = flag; \
79 allocate_toolbar_item_id (struct frame* f, struct toolbar_button* button,
82 /* hmm what do we generate an id based on */
83 int id = TOOLBAR_ITEM_ID_BITS (internal_hash (button->callback, 0));
84 while (!NILP (Fgethash (make_int (id),
85 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil)))
87 id = TOOLBAR_ITEM_ID_BITS (id + 1);
93 mswindows_clear_toolbar (struct frame *f, enum toolbar_pos pos,
96 HIMAGELIST ilist=NULL;
98 HWND toolbarwnd = TOOLBAR_HANDLE(f, pos);
103 /* Delete the buttons and remove the command from the hash table*/
104 i = SendMessage (toolbarwnd, TB_BUTTONCOUNT, 0, 0);
105 for (i--; i >= 0; i--)
107 SendMessage (toolbarwnd, TB_GETBUTTON, (WPARAM)i,
109 Fremhash(make_int(info.idCommand),
110 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE(f));
111 SendMessage (toolbarwnd, TB_DELETEBUTTON, (WPARAM)i, 0);
114 /* finally get rid of the image list assuming it clears up its
116 SendMessage (toolbarwnd, TB_GETIMAGELIST, 0, (LONG) &ilist);
119 ImageList_Destroy(ilist);
121 SendMessage (toolbarwnd, TB_SETIMAGELIST, 0, (LPARAM)NULL);
123 ShowWindow(toolbarwnd, SW_HIDE);
126 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM (f, pos) = 0;
127 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
131 mswindows_output_toolbar (struct frame *f, enum toolbar_pos pos)
133 int x, y, bar_width, bar_height, vert;
134 int width=-1, height=-1, bmwidth=0, bmheight=0, maxbmwidth, maxbmheight;
136 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
137 Lisp_Object button, glyph, instance;
138 Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
141 int shadow_thickness = 2; /* get this from somewhere else? */
142 int window_frame_width = 3;
143 int padding = (border_width + shadow_thickness) * 2;
144 unsigned int checksum=0;
145 struct window *w = XWINDOW (window);
146 TBBUTTON* button_tbl, *tbbutton;
147 HIMAGELIST ilist=NULL;
148 HWND toolbarwnd=NULL;
150 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 0);
152 /* ediff bogusly sets the height to 2 for some obscure X-specific
153 reason. This ensures that we only try and output a toolbar for
155 if (bar_width < MSWINDOWS_MINIMUM_TOOLBAR_SIZE
157 bar_height < MSWINDOWS_MINIMUM_TOOLBAR_SIZE)
165 toolbarwnd = TOOLBAR_HANDLE (f,pos);
167 /* set button sizes based on bar size */
172 width = height = bar_width
173 - (window_frame_width + shadow_thickness) * 2;
176 width = height = bar_width;
178 maxbmwidth = maxbmheight = width - padding;
184 height = width = bar_height
185 - (window_frame_width + shadow_thickness) * 2;
188 width = height = bar_height;
190 maxbmwidth = maxbmheight = width - padding;
193 button = FRAME_TOOLBAR_BUTTONS (f, pos);
195 /* First loop over all of the buttons to determine how many there
196 are. This loop will also make sure that all instances are
197 instantiated so when we actually output them they will come up
199 while (!NILP (button))
202 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
203 checksum = HASH5 (checksum,
204 internal_hash (get_toolbar_button_glyph(w, tb), 0),
205 internal_hash (tb->callback, 0),
207 LISP_HASH (w->toolbar_buttons_captioned_p));
212 /* only rebuild if something has changed */
213 if (!toolbarwnd || FRAME_MSWINDOWS_TOOLBAR_CHECKSUM(f,pos)!=checksum)
215 /* remove the old one */
216 mswindows_clear_toolbar (f, pos, 0);
218 FRAME_MSWINDOWS_TOOLBAR_CHECKSUM (f, pos)=checksum;
220 /* build up the data required by win32 fns. */
221 button_tbl = xnew_array_and_zero (TBBUTTON, nbuttons);
222 button = FRAME_TOOLBAR_BUTTONS (f, pos);
223 tbbutton = button_tbl;
225 while (!NILP (button))
227 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
228 HBITMAP bitmap=NULL, mask=NULL;
232 tbbutton->fsStyle = TBSTYLE_SEP;
235 tbbutton->idCommand = allocate_toolbar_item_id (f, tb, pos);
236 /* currently we output the toolbar again with disabled
237 buttons it might be good to use the ms disabled code
238 instead but that means another image list, so we'll stick
239 with the emacs model. */
240 tbbutton->fsState = tb->enabled ? TBSTATE_ENABLED :
241 TBSTATE_INDETERMINATE;
242 tbbutton->fsStyle = TBSTYLE_BUTTON;
246 /* mess with the button image */
247 glyph = get_toolbar_button_glyph (w, tb);
250 instance = glyph_image_instance (glyph, window,
255 if (IMAGE_INSTANCEP (instance))
257 Lisp_Image_Instance* p = XIMAGE_INSTANCE (instance);
259 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
261 /* we are going to honor the toolbar settings
262 and resize the bitmaps accordingly if they are
263 too big. If they are too small we leave them
264 and pad the difference - unless a different size
265 crops up in the middle, at which point we *have*
266 to resize since the ImageList won't cope.*/
270 IMAGE_INSTANCE_PIXMAP_WIDTH (p) != bmwidth)
274 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) != bmheight)
276 IMAGE_INSTANCE_PIXMAP_WIDTH (p) > maxbmwidth
278 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > maxbmheight)
281 bmheight = min (maxbmheight,
282 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
284 bmwidth = min (maxbmwidth,
285 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
287 if (! (bitmap = mswindows_create_resized_bitmap
288 (p, f, bmwidth, bmheight)))
291 if (ilist) ImageList_Destroy (ilist);
292 signal_simple_error ("Couldn't resize pixmap",
295 /* we don't care if the mask fails */
296 mask = mswindows_create_resized_mask
297 (p, f, bmwidth, bmheight);
302 bmwidth = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
304 bmheight = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
307 /* need to build an image list for the bitmaps */
308 if (!ilist && !(ilist = ImageList_Create
310 (IMAGE_INSTANCE_MSWINDOWS_MASK (p)
311 ? ILC_MASK : 0) | ILC_COLOR24,
312 nbuttons, nbuttons * 2 )))
315 signal_simple_error ("Couldn't create image list",
319 /* make the mask actually do something */
320 ImageList_SetBkColor (ilist, CLR_NONE);
321 /* add a bitmap to the list */
322 if ((tbbutton->iBitmap =
326 : IMAGE_INSTANCE_MSWINDOWS_BITMAP (p),
328 : IMAGE_INSTANCE_MSWINDOWS_MASK (p))) < 0)
331 if (ilist) ImageList_Destroy (ilist);
333 ("couldn't add image to image list", instance);
335 /* we're done with these now */
336 DeleteObject (bitmap);
341 Fputhash (make_int (tbbutton->idCommand),
342 button, FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
345 /* now fix up the button size */
349 tb->border_width = border_width;
350 tb->width = width + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
351 tb->height = height + MSWINDOWS_BUTTON_SHADOW_THICKNESS * 2;
356 tb->height = MSWINDOWS_BLANK_SIZE;
358 tb->width = MSWINDOWS_BLANK_SIZE;
365 /* move on to the next button */
370 button = FRAME_TOOLBAR_BUTTONS (f, pos);
372 /* create the toolbar window? */
376 CreateWindowEx ( WS_EX_WINDOWEDGE,
380 | (style_3d ? WS_DLGFRAME : 0)
383 | CCS_NOPARENTALIGN | CCS_NODIVIDER
385 x, y, bar_width, bar_height,
386 FRAME_MSWINDOWS_HANDLE (f),
387 (HMENU)(TOOLBAR_ID_BIAS + pos),
392 ImageList_Destroy (ilist);
393 error ("couldn't create toolbar");
396 /* finally populate with images */
397 if (SendMessage (toolbarwnd, TB_BUTTONSTRUCTSIZE,
398 (WPARAM)sizeof(TBBUTTON), (LPARAM)0) == -1)
400 mswindows_clear_toolbar (f, pos, 0);
401 error ("couldn't set button structure size");
405 height = min (bmheight + padding, height);
407 width = min (bmwidth + padding, width);
409 /* pad the buttons */
410 SendMessage (toolbarwnd, TB_SETPADDING,
411 0, MAKELPARAM(width - bmwidth, height - bmheight));
413 /* set the size of buttons */
414 SendMessage (toolbarwnd, TB_SETBUTTONSIZE, 0,
415 (LPARAM)MAKELONG (width, height));
417 /* set the size of bitmaps */
418 SendMessage (toolbarwnd, TB_SETBITMAPSIZE, 0,
419 (LPARAM)MAKELONG (bmwidth, bmheight));
421 /* tell it we've done it */
422 SendMessage (toolbarwnd, TB_AUTOSIZE, 0, 0);
424 /* finally populate with images */
425 if (!SendMessage (toolbarwnd, TB_ADDBUTTONS,
426 (WPARAM)nbuttons, (LPARAM)button_tbl))
428 mswindows_clear_toolbar (f, pos, 0);
429 error ("couldn't add button list to toolbar");
432 /* vertical toolbars need more rows */
436 SendMessage (toolbarwnd, TB_SETROWS,
437 MAKEWPARAM(nbuttons, FALSE), (LPARAM)&tmp);
443 SendMessage (toolbarwnd, TB_SETROWS, MAKEWPARAM(1, FALSE),
447 /* finally populate with images */
448 if (SendMessage (toolbarwnd, TB_SETIMAGELIST, 0,
451 SendMessage (toolbarwnd, TB_SETDISABLEDIMAGELIST, 0,
454 mswindows_clear_toolbar (f, pos, 0);
455 error ("couldn't add image list to toolbar");
458 /* now display the window */
459 ShowWindow (toolbarwnd, SW_SHOW);
460 /* no idea why this is necessary but initial display will not
462 mswindows_move_toolbar (f, pos);
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_redraw_frame_toolbars (struct frame *f)
530 mswindows_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
531 FRAME_PIXHEIGHT (f));
535 mswindows_initialize_frame_toolbars (struct frame *f)
541 mswindows_output_frame_toolbars (struct frame *f)
543 assert (FRAME_MSWINDOWS_P (f));
545 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
546 mswindows_output_toolbar (f, TOP_TOOLBAR);
547 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
548 mswindows_output_toolbar (f, BOTTOM_TOOLBAR);
549 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
550 mswindows_output_toolbar (f, LEFT_TOOLBAR);
551 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
552 mswindows_output_toolbar (f, RIGHT_TOOLBAR);
556 mswindows_clear_frame_toolbars (struct frame *f)
558 assert (FRAME_MSWINDOWS_P (f));
560 if (f->top_toolbar_was_visible
561 && !FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
562 mswindows_clear_toolbar (f, TOP_TOOLBAR, 0);
563 if (f->bottom_toolbar_was_visible
564 && !FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
565 mswindows_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
566 if (f->left_toolbar_was_visible
567 && !FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
568 mswindows_clear_toolbar (f, LEFT_TOOLBAR, 0);
569 if (f->right_toolbar_was_visible
570 && !FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
571 mswindows_clear_toolbar (f, RIGHT_TOOLBAR, 0);
575 mswindows_free_frame_toolbars (struct frame *f)
578 #define DELETE_TOOLBAR(pos) \
579 mswindows_clear_toolbar(f, pos, 0); \
580 if ((twnd=GetDlgItem(FRAME_MSWINDOWS_HANDLE(f), \
581 TOOLBAR_ID_BIAS + pos))) \
584 DELETE_TOOLBAR(TOP_TOOLBAR);
585 DELETE_TOOLBAR(BOTTOM_TOOLBAR);
586 DELETE_TOOLBAR(LEFT_TOOLBAR);
587 DELETE_TOOLBAR(RIGHT_TOOLBAR);
588 #undef DELETE_TOOLBAR
591 /* map toolbar hwnd to pos*/
592 static int mswindows_find_toolbar_pos(struct frame* f, HWND ctrl)
594 int id = GetDlgCtrlID(ctrl);
595 return id ? id - TOOLBAR_ID_BIAS : -1;
599 mswindows_get_toolbar_button_text ( struct frame* f, int command_id )
601 Lisp_Object button = Fgethash (make_int (command_id),
602 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
606 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
607 return tb->help_string;
613 * Return value is Qt if we have dispatched the command,
614 * or Qnil if id has not been mapped to a callback.
615 * Window procedure may try other targets to route the
616 * command if we return nil
619 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id)
621 /* Try to map the command id through the proper hash table */
622 Lisp_Object button, data, fn, arg, frame;
624 button = Fgethash (make_int (id),
625 FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f), Qnil);
630 data = XTOOLBAR_BUTTON (button)->callback;
636 /* Ok, this is our one. Enqueue it. */
637 get_gui_callback (data, &fn, &arg);
638 XSETFRAME (frame, f);
639 mswindows_enqueue_misc_user_event (frame, fn, arg);
644 /************************************************************************/
646 /************************************************************************/
649 console_type_create_toolbar_mswindows (void)
651 CONSOLE_HAS_METHOD (mswindows, output_frame_toolbars);
652 CONSOLE_HAS_METHOD (mswindows, clear_frame_toolbars);
653 CONSOLE_HAS_METHOD (mswindows, initialize_frame_toolbars);
654 CONSOLE_HAS_METHOD (mswindows, free_frame_toolbars);
655 CONSOLE_HAS_METHOD (mswindows, redraw_exposed_toolbars);
656 CONSOLE_HAS_METHOD (mswindows, redraw_frame_toolbars);