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 \
341 if (width && height) \
346 tb->height = height; \
347 tb->border_width = border_width; \
348 tb->vertical = vert; \
350 if (tb->blank || NILP (tb->up_glyph)) \
352 int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0); \
353 gtk_draw_blank_toolbar_button (f, x, y, width, \
355 border_width, vert); \
358 gtk_output_toolbar_button (f, button); \
367 if ((vert && y == max_pixpos) || (!vert && x == max_pixpos)) \
374 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
379 (frame)->top_toolbar_was_visible = flag; \
381 case BOTTOM_TOOLBAR: \
382 (frame)->bottom_toolbar_was_visible = flag; \
385 (frame)->left_toolbar_was_visible = flag; \
387 case RIGHT_TOOLBAR: \
388 (frame)->right_toolbar_was_visible = flag; \
396 gtk_output_toolbar (struct frame *f, enum toolbar_pos pos)
398 int x, y, bar_width, bar_height, vert;
399 int max_pixpos, right_size, right_start, blank_size;
400 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
401 Lisp_Object button, window;
402 GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
403 GdkGC *background_gc = get_toolbar_gc (f);
405 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
406 window = FRAME_LAST_NONMINIBUF_WINDOW (f);
409 gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
410 (vert ? bar_width : border_width),
411 (vert ? border_width : bar_height));
412 gdk_draw_rectangle (x_win, background_gc, TRUE,
413 (vert ? x : x + bar_width - border_width),
414 (vert ? y + bar_height - border_width : y),
415 (vert ? bar_width : border_width),
416 (vert ? border_width : bar_height));
420 max_pixpos = y + bar_height - border_width;
425 max_pixpos = x + bar_width - border_width;
429 button = FRAME_TOOLBAR_BUTTONS (f, pos);
432 /* First loop over all of the buttons to determine how much room we
433 need for left hand and right hand buttons. This loop will also
434 make sure that all instances are instantiated so when we actually
435 output them they will come up immediately. */
436 while (!NILP (button))
438 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
439 int size = gtk_get_button_size (f, window, tb, vert, pos);
447 button = FRAME_TOOLBAR_BUTTONS (f, pos);
449 /* Loop over the left buttons, updating and outputting them. */
450 GTK_OUTPUT_BUTTONS_LOOP (1);
452 /* Now determine where the right buttons start. */
453 right_start = max_pixpos - right_size;
454 if (right_start < (vert ? y : x))
455 right_start = (vert ? y : x);
457 /* Output the blank which goes from the end of the left buttons to
458 the start of the right. */
459 blank_size = right_start - (vert ? y : x);
476 * Use a 3D pushright separator only if there isn't a toolbar
477 * border. A flat separator meshes with the border and looks
480 gtk_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
489 /* Loop over the right buttons, updating and outputting them. */
490 GTK_OUTPUT_BUTTONS_LOOP (0);
496 XSETFRAME (frame, f);
497 redisplay_clear_region (frame,
498 DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
502 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
508 gtk_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
511 int x, y, width, height, vert;
513 get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
514 XSETFRAME (frame, f);
516 /* The thickness_change parameter is used by the toolbar resize routines
517 to clear any excess toolbar if the size shrinks. */
518 if (thickness_change < 0)
520 if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
522 x = x + width + thickness_change;
523 width = -thickness_change;
527 y = y + height + thickness_change;
528 height = -thickness_change;
532 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
534 redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
539 gtk_output_frame_toolbars (struct frame *f)
541 assert (FRAME_GTK_P (f));
543 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
544 gtk_output_toolbar (f, TOP_TOOLBAR);
545 else if (f->top_toolbar_was_visible)
546 gtk_clear_toolbar (f, TOP_TOOLBAR, 0);
548 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
549 gtk_output_toolbar (f, BOTTOM_TOOLBAR);
550 else if (f->bottom_toolbar_was_visible)
551 gtk_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
553 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
554 gtk_output_toolbar (f, LEFT_TOOLBAR);
555 else if (f->left_toolbar_was_visible)
556 gtk_clear_toolbar (f, LEFT_TOOLBAR, 0);
558 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
559 gtk_output_toolbar (f, RIGHT_TOOLBAR);
560 else if (f->right_toolbar_was_visible)
561 gtk_clear_toolbar (f, RIGHT_TOOLBAR, 0);
565 gtk_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y,
566 int width, int height)
568 int bar_x, bar_y, bar_width, bar_height, vert;
569 Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
571 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
574 if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
576 if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
579 while (!NILP (button))
581 struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
585 if (((tb->y + tb->height) > y) && (tb->y < (y + height)))
588 /* If this is true we have gone past the exposed region. */
589 if (tb->y > (y + height))
594 if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
597 /* If this is true we have gone past the exposed region. */
598 if (tb->x > (x + width))
605 /* Even if none of the buttons is in the area, the blank region at
606 the very least must be because the first thing we did is verify
607 that some portion of the toolbar is in the exposed region. */
608 gtk_output_toolbar (f, pos);
612 gtk_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
615 assert (FRAME_GTK_P (f));
617 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
618 gtk_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height);
620 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
621 gtk_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height);
623 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
624 gtk_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height);
626 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
627 gtk_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height);
631 gtk_redraw_frame_toolbars (struct frame *f)
633 /* There are certain startup paths that lead to update_EmacsFrame in
634 faces.c being called before a new frame is fully initialized. In
635 particular before we have actually mapped it. That routine can
636 call this one. So, we need to make sure that the frame is
637 actually ready before we try and draw all over it. */
639 if (GTK_WIDGET_REALIZED (FRAME_GTK_TEXT_WIDGET (f)))
640 gtk_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
641 FRAME_PIXHEIGHT (f));
646 gtk_initialize_frame_toolbars (struct frame *f)
650 /* This only calls one function but we go ahead and create this in
651 case we ever do decide that we need to do more work. */
653 gtk_free_frame_toolbars (struct frame *f)
658 /************************************************************************/
660 /************************************************************************/
663 console_type_create_toolbar_gtk (void)
665 CONSOLE_HAS_METHOD (gtk, output_frame_toolbars);
666 CONSOLE_HAS_METHOD (gtk, initialize_frame_toolbars);
667 CONSOLE_HAS_METHOD (gtk, free_frame_toolbars);
668 CONSOLE_HAS_METHOD (gtk, output_toolbar_button);
669 CONSOLE_HAS_METHOD (gtk, redraw_exposed_toolbars);
670 CONSOLE_HAS_METHOD (gtk, redraw_frame_toolbars);