1 /* toolbar implementation -- X 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.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
29 #include "console-gtk.h"
30 #include "glyphs-gtk.h"
31 #include "objects-gtk.h"
32 #include "gtk-xemacs.h"
33 #include "gccache-gtk.h"
40 extern GdkGC *gtk_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
41 Lisp_Object bg_pmap, Lisp_Object lwidth);
43 static GdkGC *get_toolbar_gc (struct frame *f)
50 fg = Fspecifier_instance (Fget (Vtoolbar_face, Qforeground, Qnil), frame, Qnil, Qnil);
51 bg = Fspecifier_instance (Fget (Vtoolbar_face, Qbackground, Qnil), frame, Qnil, Qnil);
53 /* Need to swap the foreground/background here or most themes look bug ugly */
54 return (gtk_get_gc (XDEVICE (FRAME_DEVICE (f)), Qnil, bg, fg, Qnil, Qnil));
58 gtk_draw_blank_toolbar_button (struct frame *f, int x, int y, int width,
59 int height, int threed, int border_width,
62 GtkXEmacs *ef = GTK_XEMACS (FRAME_GTK_TEXT_WIDGET (f));
63 int sx = x, sy = y, swidth = width, sheight = height;
64 GdkWindow *x_win = GTK_WIDGET (ef)->window;
65 GdkGC *background_gc = get_toolbar_gc (f);
70 swidth -= 2 * border_width;
75 sheight -= 2 * border_width;
78 /* Blank the entire area. */
79 gdk_draw_rectangle (x_win, background_gc, TRUE, sx, sy, swidth, sheight);
81 /* Draw the outline. */
83 gtk_output_shadows (f, sx, sy, swidth, sheight, 2);
86 gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
87 (vertical ? border_width : width),
88 (vertical ? height : border_width));
89 gdk_draw_rectangle (x_win, background_gc, TRUE,
90 (vertical ? sx + swidth : x),
91 (vertical ? y : sy + sheight),
92 (vertical ? border_width : width),
93 (vertical ? height : border_width));
97 gtk_output_toolbar_button (struct frame *f, Lisp_Object button)
99 int shadow_thickness = 2;
100 int x_adj, y_adj, width_adj, height_adj;
101 GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
102 GdkGC *background_gc = get_toolbar_gc (f);
103 Lisp_Object instance, frame, window, glyph;
104 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
105 struct Lisp_Image_Instance *p;
107 int vertical = tb->vertical;
108 int border_width = tb->border_width;
112 x_adj = border_width;
113 width_adj = - 2 * border_width;
121 y_adj = border_width;
122 height_adj = - 2 * border_width;
125 XSETFRAME (frame, f);
126 window = FRAME_LAST_NONMINIBUF_WINDOW (f);
127 w = XWINDOW (window);
129 glyph = get_toolbar_button_glyph (w, tb);
135 shadow_thickness = -2;
139 shadow_thickness = 2;
144 shadow_thickness = 0;
147 background_gc = get_toolbar_gc (f);
149 /* Clear the entire area. */
150 gdk_draw_rectangle (x_win, background_gc, TRUE,
153 tb->width + width_adj,
154 tb->height + height_adj);
156 /* Draw the outline. */
157 if (shadow_thickness)
158 gtk_output_shadows (f, tb->x + x_adj, tb->y + y_adj,
159 tb->width + width_adj, tb->height + height_adj,
163 gdk_draw_rectangle (x_win, background_gc, TRUE, tb->x, tb->y,
164 (vertical ? border_width : tb->width),
165 (vertical ? tb->height : border_width));
167 gdk_draw_rectangle (x_win, background_gc, TRUE,
168 (vertical ? tb->x + tb->width - border_width : tb->x),
169 (vertical ? tb->y : tb->y + tb->height - border_width),
170 (vertical ? border_width : tb->width),
171 (vertical ? tb->height : border_width));
173 background_gc = get_toolbar_gc (f);
175 /* #### It is currently possible for users to trash us by directly
176 changing the toolbar glyphs. Avoid crashing in that case. */
178 instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
182 if (IMAGE_INSTANCEP (instance))
184 int width = tb->width + width_adj - shadow_thickness * 2;
185 int height = tb->height + height_adj - shadow_thickness * 2;
186 int x_offset = x_adj + shadow_thickness;
187 int y_offset = y_adj + shadow_thickness;
189 p = XIMAGE_INSTANCE (instance);
191 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
193 if (width > (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p))
195 x_offset += ((int) (width - IMAGE_INSTANCE_PIXMAP_WIDTH (p))
197 width = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
199 if (height > (int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
201 y_offset += ((int) (height - IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
203 height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
206 gtk_output_gdk_pixmap (f, XIMAGE_INSTANCE (instance), tb->x + x_offset,
207 tb->y + y_offset, 0, 0, 0, 0, width, height,
208 0, 0, 0, background_gc);
210 else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_TEXT)
212 /* #### We need to make the face used configurable. */
213 struct face_cachel *cachel =
214 WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
215 struct display_line dl;
216 Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING (p);
217 unsigned char charsets[NUM_LEADING_BYTES];
219 struct font_metric_info fm;
221 /* This could be true if we were called via the Expose event
222 handler. Mark the button as dirty and return
224 if (f->window_face_cache_reset)
227 MARK_TOOLBAR_CHANGED;
230 buf = Dynarr_new (Emchar);
231 convert_bufbyte_string_into_emchar_dynarr
232 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
233 find_charsets_in_emchar_string (charsets, Dynarr_atp (buf, 0),
234 Dynarr_length (buf));
235 ensure_face_cachel_complete (cachel, window, charsets);
236 face_cachel_charset_font_metric_info (cachel, charsets, &fm);
238 dl.ascent = fm.ascent;
239 dl.descent = fm.descent;
240 dl.ypos = tb->y + y_offset + fm.ascent;
242 if (fm.ascent + fm.descent <= height)
244 dl.ypos += (height - fm.ascent - fm.descent) / 2;
249 dl.clip = fm.ascent + fm.descent - height;
252 gtk_output_string (w, &dl, buf, tb->x + x_offset, 0, 0, width,
253 DEFAULT_INDEX, 0, 0, 0, 0);
257 /* We silently ignore the image if it isn't a pixmap or text. */
264 gtk_get_button_size (struct frame *f, Lisp_Object window,
265 struct toolbar_button *tb, int vert, int pos)
267 int shadow_thickness = 2;
272 if (!NILP (tb->down_glyph))
273 size = XINT (tb->down_glyph);
275 size = DEFAULT_TOOLBAR_BLANK_SIZE;
279 struct window *w = XWINDOW (window);
280 Lisp_Object glyph = get_toolbar_button_glyph (w, tb);
282 /* Unless, of course, the user has done something stupid like
283 change the glyph out from under us. Use a blank placeholder
286 return XINT (f->toolbar_size[pos]);
289 size = glyph_height (glyph, window);
291 size = glyph_width (glyph, window);
296 /* If the glyph doesn't have a size we'll insert a blank
297 placeholder instead. */
298 return XINT (f->toolbar_size[pos]);
301 size += shadow_thickness * 2;
306 #define GTK_OUTPUT_BUTTONS_LOOP(left) \
308 while (!NILP (button)) \
310 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); \
311 int size, height, width; \
313 if (left && tb->pushright) \
316 size = gtk_get_button_size (f, window, tb, vert, pos); \
321 if (y + size > max_pixpos) \
322 height = max_pixpos - y; \
328 if (x + size > max_pixpos) \
329 width = max_pixpos - x; \
332 height = bar_height; \
337 || tb->width != width \
338 || tb->height != height \
340 || f->clear) /* This is clearly necessary. */ \
342 if (width && height) \
347 tb->height = height; \
348 tb->border_width = border_width; \
349 tb->vertical = vert; \
351 if (tb->blank || NILP (tb->up_glyph)) \
353 int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0); \
354 gtk_draw_blank_toolbar_button (f, x, y, width, \
356 border_width, vert); \
359 gtk_output_toolbar_button (f, button); \
368 if ((vert && y == max_pixpos) || (!vert && x == max_pixpos)) \
375 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
380 (frame)->top_toolbar_was_visible = flag; \
382 case BOTTOM_TOOLBAR: \
383 (frame)->bottom_toolbar_was_visible = flag; \
386 (frame)->left_toolbar_was_visible = flag; \
388 case RIGHT_TOOLBAR: \
389 (frame)->right_toolbar_was_visible = flag; \
397 gtk_output_toolbar (struct frame *f, enum toolbar_pos pos)
399 int x, y, bar_width, bar_height, vert;
400 int max_pixpos, right_size, right_start, blank_size;
401 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
402 Lisp_Object button, window;
403 GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
404 GdkGC *background_gc = get_toolbar_gc (f);
406 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
407 window = FRAME_LAST_NONMINIBUF_WINDOW (f);
410 gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
411 (vert ? bar_width : border_width),
412 (vert ? border_width : bar_height));
413 gdk_draw_rectangle (x_win, background_gc, TRUE,
414 (vert ? x : x + bar_width - border_width),
415 (vert ? y + bar_height - border_width : y),
416 (vert ? bar_width : border_width),
417 (vert ? border_width : bar_height));
421 max_pixpos = y + bar_height - border_width;
426 max_pixpos = x + bar_width - border_width;
430 button = FRAME_TOOLBAR_BUTTONS (f, pos);
433 /* First loop over all of the buttons to determine how much room we
434 need for left hand and right hand buttons. This loop will also
435 make sure that all instances are instantiated so when we actually
436 output them they will come up immediately. */
437 while (!NILP (button))
439 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
440 int size = gtk_get_button_size (f, window, tb, vert, pos);
448 button = FRAME_TOOLBAR_BUTTONS (f, pos);
450 /* Loop over the left buttons, updating and outputting them. */
451 GTK_OUTPUT_BUTTONS_LOOP (1);
453 /* Now determine where the right buttons start. */
454 right_start = max_pixpos - right_size;
455 if (right_start < (vert ? y : x))
456 right_start = (vert ? y : x);
458 /* Output the blank which goes from the end of the left buttons to
459 the start of the right. */
460 blank_size = right_start - (vert ? y : x);
477 * Use a 3D pushright separator only if there isn't a toolbar
478 * border. A flat separator meshes with the border and looks
481 gtk_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
490 /* Loop over the right buttons, updating and outputting them. */
491 GTK_OUTPUT_BUTTONS_LOOP (0);
497 XSETFRAME (frame, f);
498 redisplay_clear_region (frame,
499 DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
503 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
509 gtk_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
512 int x, y, width, height, vert;
514 get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
515 XSETFRAME (frame, f);
517 /* The thickness_change parameter is used by the toolbar resize routines
518 to clear any excess toolbar if the size shrinks. */
519 if (thickness_change < 0)
521 if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
523 x = x + width + thickness_change;
524 width = -thickness_change;
528 y = y + height + thickness_change;
529 height = -thickness_change;
533 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
535 redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
540 gtk_output_frame_toolbars (struct frame *f)
542 assert (FRAME_GTK_P (f));
544 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
545 gtk_output_toolbar (f, TOP_TOOLBAR);
546 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
547 gtk_output_toolbar (f, BOTTOM_TOOLBAR);
548 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
549 gtk_output_toolbar (f, LEFT_TOOLBAR);
550 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
551 gtk_output_toolbar (f, RIGHT_TOOLBAR);
555 gtk_clear_frame_toolbars (struct frame *f)
557 assert (FRAME_GTK_P (f));
559 if (f->top_toolbar_was_visible
560 && !FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
561 gtk_clear_toolbar (f, TOP_TOOLBAR, 0);
562 if (f->bottom_toolbar_was_visible
563 && !FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
564 gtk_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
565 if (f->left_toolbar_was_visible
566 && !FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
567 gtk_clear_toolbar (f, LEFT_TOOLBAR, 0);
568 if (f->right_toolbar_was_visible
569 && !FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
570 gtk_clear_toolbar (f, RIGHT_TOOLBAR, 0);
574 gtk_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y,
575 int width, int height)
577 int bar_x, bar_y, bar_width, bar_height, vert;
578 Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
580 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
583 if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
585 if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
588 while (!NILP (button))
590 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
594 if (((tb->y + tb->height) > y) && (tb->y < (y + height)))
597 /* If this is true we have gone past the exposed region. */
598 if (tb->y > (y + height))
603 if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
606 /* If this is true we have gone past the exposed region. */
607 if (tb->x > (x + width))
614 /* Even if none of the buttons is in the area, the blank region at
615 the very least must be because the first thing we did is verify
616 that some portion of the toolbar is in the exposed region. */
617 gtk_output_toolbar (f, pos);
621 gtk_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
624 assert (FRAME_GTK_P (f));
626 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
627 gtk_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height);
629 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
630 gtk_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height);
632 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
633 gtk_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height);
635 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
636 gtk_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height);
640 gtk_redraw_frame_toolbars (struct frame *f)
642 /* There are certain startup paths that lead to update_EmacsFrame in
643 faces.c being called before a new frame is fully initialized. In
644 particular before we have actually mapped it. That routine can
645 call this one. So, we need to make sure that the frame is
646 actually ready before we try and draw all over it. */
648 if (GTK_WIDGET_REALIZED (FRAME_GTK_TEXT_WIDGET (f)))
649 gtk_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
650 FRAME_PIXHEIGHT (f));
655 gtk_initialize_frame_toolbars (struct frame *f)
659 /* This only calls one function but we go ahead and create this in
660 case we ever do decide that we need to do more work. */
662 gtk_free_frame_toolbars (struct frame *f)
667 /************************************************************************/
669 /************************************************************************/
672 console_type_create_toolbar_gtk (void)
674 CONSOLE_HAS_METHOD (gtk, output_frame_toolbars);
675 CONSOLE_HAS_METHOD (gtk, clear_frame_toolbars);
676 CONSOLE_HAS_METHOD (gtk, initialize_frame_toolbars);
677 CONSOLE_HAS_METHOD (gtk, free_frame_toolbars);
678 CONSOLE_HAS_METHOD (gtk, output_toolbar_button);
679 CONSOLE_HAS_METHOD (gtk, redraw_exposed_toolbars);
680 CONSOLE_HAS_METHOD (gtk, redraw_frame_toolbars);