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 SXEmacs
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 /* Synched up with: Not in FSF. */
28 #include "console-gtk.h"
29 #include "glyphs-gtk.h"
30 #include "objects-gtk.h"
31 #include "gtk-xemacs.h"
32 #include "gccache-gtk.h"
36 #include "ui/toolbar.h"
37 #include "ui/window.h"
39 extern GdkGC *gtk_get_gc(struct device *d, Lisp_Object font, Lisp_Object fg,
40 Lisp_Object bg, Lisp_Object bg_pmap,
43 static GdkGC *get_toolbar_gc(struct frame *f)
50 fg = Fspecifier_instance(Fget(Vtoolbar_face, Qforeground, Qnil), frame,
52 bg = Fspecifier_instance(Fget(Vtoolbar_face, Qbackground, Qnil), frame,
55 /* Need to swap the foreground/background here or most themes look bug ugly */
56 return (gtk_get_gc(XDEVICE(FRAME_DEVICE(f)), Qnil, bg, fg, Qnil, Qnil));
60 gtk_draw_blank_toolbar_button(struct frame *f, int x, int y, int width,
61 int height, int threed, int border_width,
64 GtkXEmacs *ef = GTK_XEMACS(FRAME_GTK_TEXT_WIDGET(f));
65 int sx = x, sy = y, swidth = width, sheight = height;
66 GdkWindow *x_win = GTK_WIDGET(ef)->window;
67 GdkGC *background_gc = get_toolbar_gc(f);
71 swidth -= 2 * border_width;
74 sheight -= 2 * border_width;
77 /* Blank the entire area. */
78 gdk_draw_rectangle(x_win, background_gc, TRUE, sx, sy, swidth, sheight);
80 /* Draw the outline. */
82 gtk_output_shadows(f, sx, sy, swidth, sheight, 2);
85 gdk_draw_rectangle(x_win, background_gc, TRUE, x, y,
86 (vertical ? border_width : width),
87 (vertical ? height : border_width));
88 gdk_draw_rectangle(x_win, background_gc, TRUE,
89 (vertical ? sx + swidth : x),
90 (vertical ? y : sy + sheight),
91 (vertical ? border_width : width),
92 (vertical ? height : border_width));
95 static void gtk_output_toolbar_button(struct frame *f, Lisp_Object button)
97 int shadow_thickness = 2;
98 int x_adj, y_adj, width_adj, height_adj;
99 GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET(f)->window;
100 GdkGC *background_gc = get_toolbar_gc(f);
101 Lisp_Object instance, frame, window, glyph;
102 struct toolbar_button *tb = XTOOLBAR_BUTTON(button);
103 struct Lisp_Image_Instance *p;
105 int vertical = tb->vertical;
106 int border_width = tb->border_width;
109 x_adj = border_width;
110 width_adj = -2 * border_width;
116 y_adj = border_width;
117 height_adj = -2 * border_width;
121 window = FRAME_LAST_NONMINIBUF_WINDOW(f);
124 glyph = get_toolbar_button_glyph(w, tb);
128 shadow_thickness = -2;
130 shadow_thickness = 2;
133 shadow_thickness = 0;
136 background_gc = get_toolbar_gc(f);
138 /* Clear the entire area. */
139 gdk_draw_rectangle(x_win, background_gc, TRUE,
142 tb->width + width_adj, tb->height + height_adj);
144 /* Draw the outline. */
145 if (shadow_thickness)
146 gtk_output_shadows(f, tb->x + x_adj, tb->y + y_adj,
147 tb->width + width_adj,
148 tb->height + height_adj, shadow_thickness);
151 gdk_draw_rectangle(x_win, background_gc, TRUE, tb->x, tb->y,
152 (vertical ? border_width : tb->width),
153 (vertical ? tb->height : border_width));
155 gdk_draw_rectangle(x_win, background_gc, TRUE,
156 (vertical ? tb->x + tb->width -
157 border_width : tb->x),
158 (vertical ? tb->y : tb->y + tb->height -
160 (vertical ? border_width : tb->width),
161 (vertical ? tb->height : border_width));
163 background_gc = get_toolbar_gc(f);
165 /* #### It is currently possible for users to trash us by directly
166 changing the toolbar glyphs. Avoid crashing in that case. */
168 instance = glyph_image_instance(glyph, window, ERROR_ME_NOT, 1);
172 if (IMAGE_INSTANCEP(instance)) {
173 int width = tb->width + width_adj - shadow_thickness * 2;
174 int height = tb->height + height_adj - shadow_thickness * 2;
175 int x_offset = x_adj + shadow_thickness;
176 int y_offset = y_adj + shadow_thickness;
178 p = XIMAGE_INSTANCE(instance);
180 if (IMAGE_INSTANCE_PIXMAP_TYPE_P(p)) {
181 if (width > (int)IMAGE_INSTANCE_PIXMAP_WIDTH(p)) {
184 (width - IMAGE_INSTANCE_PIXMAP_WIDTH(p))
186 width = IMAGE_INSTANCE_PIXMAP_WIDTH(p);
188 if (height > (int)IMAGE_INSTANCE_PIXMAP_HEIGHT(p)) {
191 (height - IMAGE_INSTANCE_PIXMAP_HEIGHT(p))
193 height = IMAGE_INSTANCE_PIXMAP_HEIGHT(p);
196 gtk_output_gdk_pixmap(f, XIMAGE_INSTANCE(instance),
198 tb->y + y_offset, 0, 0, 0, 0,
199 width, height, 0, 0, 0,
201 } else if (IMAGE_INSTANCE_TYPE(p) == IMAGE_TEXT) {
202 /* #### We need to make the face used configurable. */
203 struct face_cachel *cachel =
204 WINDOW_FACE_CACHEL(w, DEFAULT_INDEX);
205 struct display_line dl;
206 Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING(p);
207 unsigned char charsets[NUM_LEADING_BYTES];
209 struct font_metric_info fm;
211 /* This could be true if we were called via the Expose event
212 handler. Mark the button as dirty and return
214 if (f->window_face_cache_reset) {
216 MARK_TOOLBAR_CHANGED;
219 buf = Dynarr_new(Emchar);
220 convert_bufbyte_string_into_emchar_dynarr
221 (XSTRING_DATA(string), XSTRING_LENGTH(string), buf);
222 find_charsets_in_emchar_string(charsets,
225 ensure_face_cachel_complete(cachel, window, charsets);
226 face_cachel_charset_font_metric_info(cachel, charsets,
229 dl.ascent = fm.ascent;
230 dl.descent = fm.descent;
231 dl.ypos = tb->y + y_offset + fm.ascent;
233 if (fm.ascent + fm.descent <= height) {
235 (height - fm.ascent - fm.descent) / 2;
238 dl.clip = fm.ascent + fm.descent - height;
241 gtk_output_string(w, &dl, buf, tb->x + x_offset, 0, 0,
242 width, DEFAULT_INDEX, 0, 0, 0, 0);
246 /* We silently ignore the image if it isn't a pixmap or text. */
253 gtk_get_button_size(struct frame *f, Lisp_Object window,
254 struct toolbar_button *tb, int vert, int pos)
256 int shadow_thickness = 2;
260 if (!NILP(tb->down_glyph))
261 size = XINT(tb->down_glyph);
263 size = DEFAULT_TOOLBAR_BLANK_SIZE;
265 struct window *w = XWINDOW(window);
266 Lisp_Object glyph = get_toolbar_button_glyph(w, tb);
268 /* Unless, of course, the user has done something stupid like
269 change the glyph out from under us. Use a blank placeholder
272 return XINT(f->toolbar_size[pos]);
275 size = glyph_height(glyph, window);
277 size = glyph_width(glyph, window);
281 /* If the glyph doesn't have a size we'll insert a blank
282 placeholder instead. */
283 return XINT(f->toolbar_size[pos]);
286 size += shadow_thickness * 2;
291 #define GTK_OUTPUT_BUTTONS_LOOP(left) \
293 while (!NILP (button)) \
295 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); \
296 int size, height, width; \
298 if (left && tb->pushright) \
301 size = gtk_get_button_size (f, window, tb, vert, pos); \
306 if (y + size > max_pixpos) \
307 height = max_pixpos - y; \
313 if (x + size > max_pixpos) \
314 width = max_pixpos - x; \
317 height = bar_height; \
322 || tb->width != width \
323 || tb->height != height \
325 || f->clear) /* This is clearly necessary. */ \
327 if (width && height) \
332 tb->height = height; \
333 tb->border_width = border_width; \
334 tb->vertical = vert; \
336 if (tb->blank || NILP (tb->up_glyph)) \
338 int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0); \
339 gtk_draw_blank_toolbar_button (f, x, y, width, \
341 border_width, vert); \
344 gtk_output_toolbar_button (f, button); \
353 if ((vert && y == max_pixpos) || (!vert && x == max_pixpos)) \
360 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \
365 (frame)->top_toolbar_was_visible = flag; \
367 case BOTTOM_TOOLBAR: \
368 (frame)->bottom_toolbar_was_visible = flag; \
371 (frame)->left_toolbar_was_visible = flag; \
373 case RIGHT_TOOLBAR: \
374 (frame)->right_toolbar_was_visible = flag; \
381 static void gtk_output_toolbar(struct frame *f, enum toolbar_pos pos)
383 int x, y, bar_width, bar_height, vert;
384 int max_pixpos, right_size, right_start, blank_size;
385 int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH(f, pos);
386 Lisp_Object button, window;
387 GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET(f)->window;
388 GdkGC *background_gc = get_toolbar_gc(f);
390 get_toolbar_coords(f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
391 window = FRAME_LAST_NONMINIBUF_WINDOW(f);
394 gdk_draw_rectangle(x_win, background_gc, TRUE, x, y,
395 (vert ? bar_width : border_width),
396 (vert ? border_width : bar_height));
397 gdk_draw_rectangle(x_win, background_gc, TRUE,
398 (vert ? x : x + bar_width - border_width),
399 (vert ? y + bar_height - border_width : y),
400 (vert ? bar_width : border_width),
401 (vert ? border_width : bar_height));
404 max_pixpos = y + bar_height - border_width;
407 max_pixpos = x + bar_width - border_width;
411 button = FRAME_TOOLBAR_BUTTONS(f, pos);
414 /* First loop over all of the buttons to determine how much room we
415 need for left hand and right hand buttons. This loop will also
416 make sure that all instances are instantiated so when we actually
417 output them they will come up immediately. */
418 while (!NILP(button)) {
419 struct toolbar_button *tb = XTOOLBAR_BUTTON(button);
420 int size = gtk_get_button_size(f, window, tb, vert, pos);
428 button = FRAME_TOOLBAR_BUTTONS(f, pos);
430 /* Loop over the left buttons, updating and outputting them. */
431 GTK_OUTPUT_BUTTONS_LOOP(1);
433 /* Now determine where the right buttons start. */
434 right_start = max_pixpos - right_size;
435 if (right_start < (vert ? y : x))
436 right_start = (vert ? y : x);
438 /* Output the blank which goes from the end of the left buttons to
439 the start of the right. */
440 blank_size = right_start - (vert ? y : x);
453 * Use a 3D pushright separator only if there isn't a toolbar
454 * border. A flat separator meshes with the border and looks
457 gtk_draw_blank_toolbar_button(f, x, y, width, height,
458 !border_width, border_width,
467 /* Loop over the right buttons, updating and outputting them. */
468 GTK_OUTPUT_BUTTONS_LOOP(0);
474 redisplay_clear_region(frame,
475 DEFAULT_INDEX, FRAME_PIXWIDTH(f) - 1, y,
479 SET_TOOLBAR_WAS_VISIBLE_FLAG(f, pos, 1);
485 gtk_clear_toolbar(struct frame *f, enum toolbar_pos pos, int thickness_change)
488 int x, y, width, height, vert;
490 get_toolbar_coords(f, pos, &x, &y, &width, &height, &vert, 1);
493 /* The thickness_change parameter is used by the toolbar resize routines
494 to clear any excess toolbar if the size shrinks. */
495 if (thickness_change < 0) {
496 if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR) {
497 x = x + width + thickness_change;
498 width = -thickness_change;
500 y = y + height + thickness_change;
501 height = -thickness_change;
505 SET_TOOLBAR_WAS_VISIBLE_FLAG(f, pos, 0);
507 redisplay_clear_region(frame, DEFAULT_INDEX, x, y, width, height);
511 static void gtk_output_frame_toolbars(struct frame *f)
513 assert(FRAME_GTK_P(f));
515 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE(f))
516 gtk_output_toolbar(f, TOP_TOOLBAR);
517 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE(f))
518 gtk_output_toolbar(f, BOTTOM_TOOLBAR);
519 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE(f))
520 gtk_output_toolbar(f, LEFT_TOOLBAR);
521 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE(f))
522 gtk_output_toolbar(f, RIGHT_TOOLBAR);
525 static void gtk_clear_frame_toolbars(struct frame *f)
527 assert(FRAME_GTK_P(f));
529 if (f->top_toolbar_was_visible && !FRAME_REAL_TOP_TOOLBAR_VISIBLE(f))
530 gtk_clear_toolbar(f, TOP_TOOLBAR, 0);
531 if (f->bottom_toolbar_was_visible
532 && !FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE(f))
533 gtk_clear_toolbar(f, BOTTOM_TOOLBAR, 0);
534 if (f->left_toolbar_was_visible && !FRAME_REAL_LEFT_TOOLBAR_VISIBLE(f))
535 gtk_clear_toolbar(f, LEFT_TOOLBAR, 0);
536 if (f->right_toolbar_was_visible
537 && !FRAME_REAL_RIGHT_TOOLBAR_VISIBLE(f))
538 gtk_clear_toolbar(f, RIGHT_TOOLBAR, 0);
542 gtk_redraw_exposed_toolbar(struct frame *f, enum toolbar_pos pos, int x, int y,
543 int width, int height)
545 int bar_x, bar_y, bar_width, bar_height, vert;
546 Lisp_Object button = FRAME_TOOLBAR_BUTTONS(f, pos);
548 get_toolbar_coords(f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
551 if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
553 if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
556 while (!NILP(button)) {
557 struct toolbar_button *tb = XTOOLBAR_BUTTON(button);
560 if (((tb->y + tb->height) > y)
561 && (tb->y < (y + height)))
564 /* If this is true we have gone past the exposed region. */
565 if (tb->y > (y + height))
568 if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
571 /* If this is true we have gone past the exposed region. */
572 if (tb->x > (x + width))
579 /* Even if none of the buttons is in the area, the blank region at
580 the very least must be because the first thing we did is verify
581 that some portion of the toolbar is in the exposed region. */
582 gtk_output_toolbar(f, pos);
586 gtk_redraw_exposed_toolbars(struct frame *f, int x, int y, int width,
589 assert(FRAME_GTK_P(f));
591 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE(f))
592 gtk_redraw_exposed_toolbar(f, TOP_TOOLBAR, x, y, width, height);
594 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE(f))
595 gtk_redraw_exposed_toolbar(f, BOTTOM_TOOLBAR, x, y, width,
598 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE(f))
599 gtk_redraw_exposed_toolbar(f, LEFT_TOOLBAR, x, y, width,
602 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE(f))
603 gtk_redraw_exposed_toolbar(f, RIGHT_TOOLBAR, x, y, width,
607 static void gtk_redraw_frame_toolbars(struct frame *f)
609 /* There are certain startup paths that lead to update_EmacsFrame in
610 faces.c being called before a new frame is fully initialized. In
611 particular before we have actually mapped it. That routine can
612 call this one. So, we need to make sure that the frame is
613 actually ready before we try and draw all over it. */
615 if (GTK_WIDGET_REALIZED(FRAME_GTK_TEXT_WIDGET(f)))
616 gtk_redraw_exposed_toolbars(f, 0, 0, FRAME_PIXWIDTH(f),
620 static void gtk_initialize_frame_toolbars(struct frame *f)
624 /* This only calls one function but we go ahead and create this in
625 case we ever do decide that we need to do more work. */
626 static void gtk_free_frame_toolbars(struct frame *f)
630 /************************************************************************/
632 /************************************************************************/
634 void console_type_create_toolbar_gtk(void)
636 CONSOLE_HAS_METHOD(gtk, output_frame_toolbars);
637 CONSOLE_HAS_METHOD(gtk, clear_frame_toolbars);
638 CONSOLE_HAS_METHOD(gtk, initialize_frame_toolbars);
639 CONSOLE_HAS_METHOD(gtk, free_frame_toolbars);
640 CONSOLE_HAS_METHOD(gtk, output_toolbar_button);
641 CONSOLE_HAS_METHOD(gtk, redraw_exposed_toolbars);
642 CONSOLE_HAS_METHOD(gtk, redraw_frame_toolbars);