Mercurial > hg > xemacs-beta
comparison src/toolbar-x.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
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. | |
6 | |
7 This file is part of XEmacs. | |
8 | |
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 | |
12 later version. | |
13 | |
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 | |
17 for more details. | |
18 | |
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. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
25 | |
26 #include <config.h> | |
27 #include "lisp.h" | |
28 | |
29 #include "console-x.h" | |
30 #include "glyphs-x.h" | |
31 #include "objects-x.h" | |
32 #include "xgccache.h" | |
33 #include "EmacsFrame.h" | |
34 #include "EmacsFrameP.h" | |
35 #include "EmacsManager.h" | |
36 | |
37 #include "faces.h" | |
38 #include "frame.h" | |
39 #include "toolbar.h" | |
40 #include "window.h" | |
41 | |
42 static void | |
43 x_draw_blank_toolbar_button (struct frame *f, int x, int y, int width, | |
44 int height, int threed) | |
45 { | |
46 struct device *d = XDEVICE (f->device); | |
47 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
48 int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness; | |
49 | |
50 Display *dpy = DEVICE_X_DISPLAY (d); | |
51 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f)); | |
52 GC top_shadow_gc, bottom_shadow_gc, background_gc; | |
53 | |
54 background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f); | |
55 | |
56 if (threed) | |
57 { | |
58 top_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f); | |
59 bottom_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f); | |
60 } | |
61 else | |
62 { | |
63 top_shadow_gc = background_gc; | |
64 bottom_shadow_gc = background_gc; | |
65 } | |
66 | |
67 /* Draw the outline. */ | |
68 x_output_shadows (f, x, y, width, height, top_shadow_gc, | |
69 bottom_shadow_gc, background_gc, shadow_thickness); | |
70 | |
71 /* Blank the middle. */ | |
72 XFillRectangle (dpy, x_win, background_gc, x + shadow_thickness, | |
73 y + shadow_thickness, width - shadow_thickness * 2, | |
74 height - shadow_thickness * 2); | |
75 } | |
76 | |
77 static void | |
78 x_output_toolbar_button (struct frame *f, Lisp_Object button) | |
79 { | |
80 struct device *d = XDEVICE (f->device); | |
81 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
82 int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness; | |
83 | |
84 Display *dpy = DEVICE_X_DISPLAY (d); | |
85 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f)); | |
86 GC top_shadow_gc, bottom_shadow_gc, background_gc; | |
87 Lisp_Object instance, frame, window, glyph; | |
88 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); | |
89 struct Lisp_Image_Instance *p; | |
90 struct window *w; | |
91 | |
92 XSETFRAME (frame, f); | |
93 window = FRAME_LAST_NONMINIBUF_WINDOW (f); | |
94 w = XWINDOW (window); | |
95 | |
96 glyph = get_toolbar_button_glyph (w, tb); | |
97 | |
98 if (tb->enabled) | |
99 { | |
100 if (tb->down) | |
101 { | |
102 top_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f); | |
103 bottom_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f); | |
104 } | |
105 else | |
106 { | |
107 top_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f); | |
108 bottom_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f); | |
109 } | |
110 } | |
111 else | |
112 { | |
113 top_shadow_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f); | |
114 bottom_shadow_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f); | |
115 } | |
116 background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f); | |
117 | |
118 /* Draw the outline. */ | |
119 x_output_shadows (f, tb->x, tb->y, tb->width, tb->height, top_shadow_gc, | |
120 bottom_shadow_gc, background_gc, shadow_thickness); | |
121 | |
122 /* Clear the pixmap area. */ | |
123 XFillRectangle (dpy, x_win, background_gc, tb->x + shadow_thickness, | |
124 tb->y + shadow_thickness, tb->width - shadow_thickness * 2, | |
125 tb->height - shadow_thickness * 2); | |
126 | |
127 background_gc = FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f); | |
128 | |
129 /* #### It is currently possible for users to trash us by directly | |
130 changing the toolbar glyphs. Avoid crashing in that case. */ | |
131 if (GLYPHP (glyph)) | |
132 instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1); | |
133 else | |
134 instance = Qnil; | |
135 | |
136 if (IMAGE_INSTANCEP (instance)) | |
137 { | |
138 int width = tb->width - shadow_thickness * 2; | |
139 int height = tb->height - shadow_thickness * 2; | |
140 int x_offset = shadow_thickness; | |
141 int y_offset = shadow_thickness; | |
142 | |
143 p = XIMAGE_INSTANCE (instance); | |
144 | |
145 if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p)) | |
146 { | |
147 if (width > (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p)) | |
148 { | |
149 x_offset += ((int) (width - IMAGE_INSTANCE_PIXMAP_WIDTH (p)) | |
150 / 2); | |
151 width = IMAGE_INSTANCE_PIXMAP_WIDTH (p); | |
152 } | |
153 if (height > (int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p)) | |
154 { | |
155 y_offset += ((int) (height - IMAGE_INSTANCE_PIXMAP_HEIGHT (p)) | |
156 / 2); | |
157 height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p); | |
158 } | |
159 | |
160 x_output_x_pixmap (f, XIMAGE_INSTANCE (instance), tb->x + x_offset, | |
161 tb->y + y_offset, 0, 0, 0, 0, width, height, | |
162 0, 0, 0, background_gc); | |
163 } | |
164 else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_TEXT) | |
165 { | |
166 /* #### We need to make the face used configurable. */ | |
167 struct face_cachel *cachel = | |
168 WINDOW_FACE_CACHEL (w, DEFAULT_INDEX); | |
169 struct display_line dl; | |
170 Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING (p); | |
171 unsigned char charsets[NUM_LEADING_BYTES]; | |
172 emchar_dynarr *buf; | |
173 struct font_metric_info fm; | |
174 | |
175 /* This could be true if we were called via the Expose event | |
176 handler. Mark the button as dirty and return | |
177 immediately. */ | |
178 if (f->window_face_cache_reset) | |
179 { | |
180 tb->dirty = 1; | |
181 MARK_TOOLBAR_CHANGED; | |
182 return; | |
183 } | |
184 buf = Dynarr_new (Emchar); | |
185 convert_bufbyte_string_into_emchar_dynarr | |
186 (string_data (XSTRING (string)), | |
187 string_length (XSTRING (string)), | |
188 buf); | |
189 find_charsets_in_emchar_string (charsets, Dynarr_atp (buf, 0), | |
190 Dynarr_length (buf)); | |
191 ensure_face_cachel_complete (cachel, window, charsets); | |
192 face_cachel_charset_font_metric_info (cachel, charsets, &fm); | |
193 | |
194 dl.ascent = fm.ascent; | |
195 dl.descent = fm.descent; | |
196 dl.ypos = tb->y + y_offset + fm.ascent; | |
197 | |
198 if (fm.ascent + fm.descent <= height) | |
199 { | |
200 dl.ypos += (height - fm.ascent - fm.descent) / 2; | |
201 dl.clip = 0; | |
202 } | |
203 else | |
204 { | |
205 dl.clip = fm.ascent + fm.descent - height; | |
206 } | |
207 | |
208 x_output_string (w, &dl, buf, tb->x + x_offset, 0, 0, width, | |
209 DEFAULT_INDEX, 0, 0, 0, 0); | |
210 Dynarr_free (buf); | |
211 } | |
212 | |
213 /* We silently ignore the image if it isn't a pixmap or text. */ | |
214 } | |
215 | |
216 tb->dirty = 0; | |
217 } | |
218 | |
219 static int | |
220 x_get_button_size (struct frame *f, Lisp_Object window, | |
221 struct toolbar_button *tb, int vert, int pos) | |
222 { | |
223 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
224 int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness; | |
225 int size; | |
226 | |
227 if (tb->blank) | |
228 { | |
229 if (!NILP (tb->down_glyph)) | |
230 size = XINT (tb->down_glyph); | |
231 else | |
232 size = DEFAULT_TOOLBAR_BLANK_SIZE; | |
233 } | |
234 else | |
235 { | |
236 struct window *w = XWINDOW (window); | |
237 Lisp_Object glyph = get_toolbar_button_glyph (w, tb); | |
238 | |
239 /* Unless, of course, the user has done something stupid like | |
240 change the glyph out from under us. Use a blank placeholder | |
241 in that case. */ | |
242 if (NILP (glyph)) | |
243 return XINT (f->toolbar_size[pos]); | |
244 | |
245 if (vert) | |
246 size = glyph_height (glyph, Vdefault_face, 0, window); | |
247 else | |
248 size = glyph_width (glyph, Vdefault_face, 0, window); | |
249 } | |
250 | |
251 if (!size) | |
252 { | |
253 /* If the glyph doesn't have a size we'll insert a blank | |
254 placeholder instead. */ | |
255 return XINT (f->toolbar_size[pos]); | |
256 } | |
257 | |
258 size += shadow_thickness * 2; | |
259 | |
260 return (size); | |
261 } | |
262 | |
263 #define X_OUTPUT_BUTTONS_LOOP(left) \ | |
264 do { \ | |
265 while (!NILP (button)) \ | |
266 { \ | |
267 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); \ | |
268 int size, height, width; \ | |
269 \ | |
270 if (left && tb->pushright) \ | |
271 break; \ | |
272 \ | |
273 size = x_get_button_size (f, window, tb, vert, pos); \ | |
274 \ | |
275 if (vert) \ | |
276 { \ | |
277 width = bar_width; \ | |
278 if (y + size > max_pixpos) \ | |
279 height = max_pixpos - y; \ | |
280 else \ | |
281 height = size; \ | |
282 } \ | |
283 else \ | |
284 { \ | |
285 if (x + size > max_pixpos) \ | |
286 width = max_pixpos - x; \ | |
287 else \ | |
288 width = size; \ | |
289 height = bar_height; \ | |
290 } \ | |
291 \ | |
292 if (tb->x != x \ | |
293 || tb->y != y \ | |
294 || tb->width != width \ | |
295 || tb->height != height \ | |
296 || tb->dirty) \ | |
297 { \ | |
298 if (width && height) \ | |
299 { \ | |
300 tb->x = x; \ | |
301 tb->y = y; \ | |
302 tb->width = width; \ | |
303 tb->height = height; \ | |
304 \ | |
305 if (tb->blank || NILP (tb->up_glyph)) \ | |
306 { \ | |
307 int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0); \ | |
308 x_draw_blank_toolbar_button (f, x, y, width, \ | |
309 height, threed); \ | |
310 } \ | |
311 else \ | |
312 x_output_toolbar_button (f, button); \ | |
313 } \ | |
314 } \ | |
315 \ | |
316 if (vert) \ | |
317 y += height; \ | |
318 else \ | |
319 x += width; \ | |
320 \ | |
321 if ((vert && y == max_pixpos) || (!vert && x == max_pixpos)) \ | |
322 button = Qnil; \ | |
323 else \ | |
324 button = tb->next; \ | |
325 } \ | |
326 } while (0) | |
327 | |
328 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag) \ | |
329 do { \ | |
330 switch (pos) \ | |
331 { \ | |
332 case TOP_TOOLBAR: \ | |
333 (frame)->top_toolbar_was_visible = flag; \ | |
334 break; \ | |
335 case BOTTOM_TOOLBAR: \ | |
336 (frame)->bottom_toolbar_was_visible = flag; \ | |
337 break; \ | |
338 case LEFT_TOOLBAR: \ | |
339 (frame)->left_toolbar_was_visible = flag; \ | |
340 break; \ | |
341 case RIGHT_TOOLBAR: \ | |
342 (frame)->right_toolbar_was_visible = flag; \ | |
343 break; \ | |
344 default: \ | |
345 abort (); \ | |
346 } \ | |
347 } while (0) | |
348 | |
349 static void | |
350 x_output_toolbar (struct frame *f, enum toolbar_pos pos) | |
351 { | |
352 struct device *d = XDEVICE (f->device); | |
353 int x, y, bar_width, bar_height, vert; | |
354 int max_pixpos, right_size, right_start, blank_size; | |
355 Lisp_Object button, window; | |
356 | |
357 get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1); | |
358 window = FRAME_LAST_NONMINIBUF_WINDOW (f); | |
359 | |
360 if (vert) | |
361 max_pixpos = y + bar_height; | |
362 else | |
363 max_pixpos = x + bar_width; | |
364 | |
365 button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons; | |
366 right_size = 0; | |
367 | |
368 /* First loop over all of the buttons to determine how much room we | |
369 need for left hand and right hand buttons. This loop will also | |
370 make sure that all instances are instantiated so when we actually | |
371 output them they will come up immediately. */ | |
372 while (!NILP (button)) | |
373 { | |
374 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); | |
375 int size = x_get_button_size (f, window, tb, vert, pos); | |
376 | |
377 if (tb->pushright) | |
378 right_size += size; | |
379 | |
380 button = tb->next; | |
381 } | |
382 | |
383 button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons; | |
384 | |
385 /* Loop over the left buttons, updating and outputting them. */ | |
386 X_OUTPUT_BUTTONS_LOOP (1); | |
387 | |
388 /* Now determine where the right buttons start. */ | |
389 right_start = max_pixpos - right_size; | |
390 if (right_start < (vert ? y : x)) | |
391 right_start = (vert ? y : x); | |
392 | |
393 /* Output the blank which goes from the end of the left buttons to | |
394 the start of the right. */ | |
395 blank_size = right_start - (vert ? y : x); | |
396 if (blank_size) | |
397 { | |
398 int height, width; | |
399 | |
400 if (vert) | |
401 { | |
402 width = bar_width; | |
403 height = blank_size; | |
404 } | |
405 else | |
406 { | |
407 width = blank_size; | |
408 height = bar_height; | |
409 } | |
410 | |
411 x_draw_blank_toolbar_button (f, x, y, width, height, 1); | |
412 | |
413 if (vert) | |
414 y += height; | |
415 else | |
416 x += width; | |
417 } | |
418 | |
419 /* Loop over the right buttons, updating and outputting them. */ | |
420 X_OUTPUT_BUTTONS_LOOP (0); | |
421 | |
422 if (!vert) | |
423 { | |
424 Lisp_Object frame; | |
425 | |
426 XSETFRAME (frame, f); | |
427 DEVMETH (d, clear_region, (frame, | |
428 DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1, | |
429 bar_height)); | |
430 } | |
431 | |
432 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1); | |
433 | |
434 XFlush (DEVICE_X_DISPLAY (d)); | |
435 } | |
436 | |
437 static void | |
438 x_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change) | |
439 { | |
440 Lisp_Object frame = Qnil; | |
441 struct device *d = XDEVICE (f->device); | |
442 int x, y, width, height, vert; | |
443 | |
444 get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1); | |
445 XSETFRAME (frame, f); | |
446 | |
447 /* The thickness_change parameter is used by the toolbar resize routines | |
448 to clear any excess toolbar if the size shrinks. */ | |
449 if (thickness_change < 0) | |
450 { | |
451 if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR) | |
452 { | |
453 x = x + width + thickness_change; | |
454 width = -thickness_change; | |
455 } | |
456 else | |
457 { | |
458 y = y + height + thickness_change; | |
459 height = -thickness_change; | |
460 } | |
461 } | |
462 | |
463 SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0); | |
464 | |
465 DEVMETH (d, clear_region, (frame, DEFAULT_INDEX, x, y, width, height)); | |
466 XFlush (DEVICE_X_DISPLAY (d)); | |
467 } | |
468 | |
469 static void | |
470 x_output_frame_toolbars (struct frame *f) | |
471 { | |
472 assert (FRAME_X_P (f)); | |
473 | |
474 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f)) | |
475 x_output_toolbar (f, TOP_TOOLBAR); | |
476 else if (f->top_toolbar_was_visible) | |
477 x_clear_toolbar (f, TOP_TOOLBAR, 0); | |
478 | |
479 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)) | |
480 x_output_toolbar (f, BOTTOM_TOOLBAR); | |
481 else if (f->bottom_toolbar_was_visible) | |
482 x_clear_toolbar (f, BOTTOM_TOOLBAR, 0); | |
483 | |
484 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f)) | |
485 x_output_toolbar (f, LEFT_TOOLBAR); | |
486 else if (f->left_toolbar_was_visible) | |
487 x_clear_toolbar (f, LEFT_TOOLBAR, 0); | |
488 | |
489 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f)) | |
490 x_output_toolbar (f, RIGHT_TOOLBAR); | |
491 else if (f->right_toolbar_was_visible) | |
492 x_clear_toolbar (f, RIGHT_TOOLBAR, 0); | |
493 } | |
494 | |
495 static void | |
496 x_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y, | |
497 int width, int height) | |
498 { | |
499 int bar_x, bar_y, bar_width, bar_height, vert; | |
500 Lisp_Object button = FRAME_TOOLBAR_DATA (f, pos)->toolbar_buttons; | |
501 | |
502 get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height, | |
503 &vert, 1); | |
504 | |
505 if (((y + height) < bar_y) || (y > (bar_y + bar_height))) | |
506 return; | |
507 if (((x + width) < bar_x) || (x > (bar_x + bar_width))) | |
508 return; | |
509 | |
510 while (!NILP (button)) | |
511 { | |
512 struct toolbar_button *tb = XTOOLBAR_BUTTON (button); | |
513 | |
514 if (vert) | |
515 { | |
516 if (((tb->y + tb->height) > y) && (tb->y < (y + height))) | |
517 tb->dirty = 1; | |
518 | |
519 /* If this is true we have gone past the exposed region. */ | |
520 if (tb->y > (y + height)) | |
521 break; | |
522 } | |
523 else | |
524 { | |
525 if (((tb->x + tb->width) > x) && (tb->x < (x + width))) | |
526 tb->dirty = 1; | |
527 | |
528 /* If this is true we have gone past the exposed region. */ | |
529 if (tb->x > (x + width)) | |
530 break; | |
531 } | |
532 | |
533 button = tb->next; | |
534 } | |
535 | |
536 /* Even if none of the buttons is in the area, the blank region at | |
537 the very least must be because the first thing we did is verify | |
538 that some portion of the toolbar is in the exposed region. */ | |
539 x_output_toolbar (f, pos); | |
540 } | |
541 | |
542 static void | |
543 x_redraw_exposed_toolbars (struct frame *f, int x, int y, int width, | |
544 int height) | |
545 { | |
546 assert (FRAME_X_P (f)); | |
547 | |
548 if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f)) | |
549 x_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height); | |
550 | |
551 if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)) | |
552 x_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height); | |
553 | |
554 if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f)) | |
555 x_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height); | |
556 | |
557 if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f)) | |
558 x_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height); | |
559 } | |
560 | |
561 static void | |
562 x_redraw_frame_toolbars (struct frame *f) | |
563 { | |
564 /* There are certain startup paths that lead to update_EmacsFrame in | |
565 faces.c being called before a new frame is fully initialized. In | |
566 particular before we have actually mapped it. That routine can | |
567 call this one. So, we need to make sure that the frame is | |
568 actually ready before we try and draw all over it. */ | |
569 | |
570 if (XtIsRealized (FRAME_X_SHELL_WIDGET (f))) | |
571 x_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f), | |
572 FRAME_PIXHEIGHT (f)); | |
573 } | |
574 | |
575 | |
576 static void | |
577 x_toolbar_size_changed_in_frame_1 (struct frame *f, enum toolbar_pos pos, | |
578 Lisp_Object old_visibility) | |
579 { | |
580 XtWidgetGeometry req, repl; | |
581 int newval; | |
582 int oldval = FRAME_X_OLD_TOOLBAR_SIZE (f, pos); | |
583 | |
584 if (NILP (f->toolbar_visible_p[pos])) | |
585 newval = 0; | |
586 else if (!f->init_finished && !INTP (f->toolbar_size[pos])) | |
587 /* the size might not be set at all if we're in the process of | |
588 creating the frame. Otherwise it better be, and we'll crash | |
589 out if not. */ | |
590 newval = 0; | |
591 else | |
592 { | |
593 Lisp_Object frame; | |
594 | |
595 XSETFRAME (frame, f); | |
596 newval = XINT (Fspecifier_instance (Vtoolbar_size[pos], frame, Qzero, | |
597 Qnil)); | |
598 } | |
599 | |
600 if (oldval == newval) | |
601 return; | |
602 | |
603 /* We want the text area to stay the same size. So, we query the | |
604 current size and then adjust it for the change in the toolbar | |
605 size. */ | |
606 | |
607 in_specifier_change_function++; | |
608 if (!in_resource_setting) | |
609 /* mirror the value in the frame resources, unless it was already | |
610 done. */ | |
611 XtVaSetValues (FRAME_X_TEXT_WIDGET (f), | |
612 pos == TOP_TOOLBAR ? XtNtopToolBarHeight : | |
613 pos == BOTTOM_TOOLBAR ? XtNbottomToolBarHeight : | |
614 pos == LEFT_TOOLBAR ? XtNleftToolBarWidth : | |
615 XtNrightToolBarWidth, | |
616 newval, 0); | |
617 if (XtIsRealized (FRAME_X_CONTAINER_WIDGET (f))) | |
618 { | |
619 int change = newval - oldval; | |
620 Lisp_Object new_visibility = f->toolbar_visible_p[pos]; | |
621 | |
622 req.request_mode = 0; | |
623 /* the query-geometry method looks at the current value of | |
624 f->toolbar_size[pos], so temporarily set it back to the old | |
625 one. If we were called because of a visibility change we | |
626 also have to temporarily restore its old status as well. */ | |
627 f->toolbar_size[pos] = make_int (oldval); | |
628 if (!EQ (old_visibility, Qzero)) | |
629 f->toolbar_visible_p[pos] = old_visibility; | |
630 XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl); | |
631 f->toolbar_size[pos] = make_int (newval); | |
632 if (!EQ (old_visibility, Qzero)) | |
633 f->toolbar_visible_p[pos] = new_visibility; | |
634 | |
635 if (change < 0) | |
636 x_clear_toolbar (f, pos, change); | |
637 if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR) | |
638 repl.width += change; | |
639 else | |
640 repl.height += change; | |
641 | |
642 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
643 EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width, | |
644 repl.height); | |
645 } | |
646 /* #### should this go within XtIsRealized()? probably not ... */ | |
647 FRAME_X_OLD_TOOLBAR_SIZE (f, pos) = newval; | |
648 in_specifier_change_function--; | |
649 } | |
650 | |
651 static void | |
652 x_toolbar_size_changed_in_frame (struct frame *f, enum toolbar_pos pos, | |
653 Lisp_Object oldval) | |
654 { | |
655 x_toolbar_size_changed_in_frame_1 (f, pos, Qzero); | |
656 } | |
657 | |
658 static void | |
659 x_toolbar_visible_p_changed_in_frame (struct frame *f, enum toolbar_pos pos, | |
660 Lisp_Object oldval) | |
661 { | |
662 x_toolbar_size_changed_in_frame_1 (f, pos, oldval); | |
663 } | |
664 | |
665 static void | |
666 x_initialize_frame_toolbar_gcs (struct frame *f) | |
667 { | |
668 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
669 XGCValues gcv; | |
670 unsigned long flags = (GCForeground | GCBackground | GCGraphicsExposures); | |
671 | |
672 gcv.foreground = ef->emacs_frame.background_toolbar_pixel; | |
673 gcv.background = ef->core.background_pixel; | |
674 gcv.graphics_exposures = False; | |
675 FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f) = | |
676 XtGetGC ((Widget) ef, flags, &gcv); | |
677 | |
678 if (ef->emacs_frame.top_toolbar_shadow_pixel == -1) | |
679 { | |
680 ef->emacs_frame.top_toolbar_shadow_pixel = | |
681 ef->emacs_frame.background_toolbar_pixel; | |
682 } | |
683 if (ef->emacs_frame.bottom_toolbar_shadow_pixel == -1) | |
684 { | |
685 ef->emacs_frame.bottom_toolbar_shadow_pixel = | |
686 ef->emacs_frame.background_toolbar_pixel; | |
687 } | |
688 | |
689 x_generate_shadow_pixels (f, &ef->emacs_frame.top_toolbar_shadow_pixel, | |
690 &ef->emacs_frame.bottom_toolbar_shadow_pixel, | |
691 ef->emacs_frame.background_toolbar_pixel, | |
692 ef->core.background_pixel); | |
693 | |
694 gcv.foreground = ef->emacs_frame.top_toolbar_shadow_pixel; | |
695 gcv.background = ef->core.background_pixel; | |
696 gcv.graphics_exposures = False; | |
697 flags = GCForeground | GCBackground | GCGraphicsExposures; | |
698 if (ef->emacs_frame.top_toolbar_shadow_pixmap) | |
699 { | |
700 gcv.fill_style = FillOpaqueStippled; | |
701 gcv.stipple = ef->emacs_frame.top_toolbar_shadow_pixmap; | |
702 flags |= GCStipple | GCFillStyle; | |
703 } | |
704 FRAME_X_TOOLBAR_TOP_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv); | |
705 | |
706 gcv.foreground = ef->emacs_frame.bottom_toolbar_shadow_pixel; | |
707 gcv.background = ef->core.background_pixel; | |
708 gcv.graphics_exposures = False; | |
709 flags = GCForeground | GCBackground | GCGraphicsExposures; | |
710 if (ef->emacs_frame.bottom_toolbar_shadow_pixmap) | |
711 { | |
712 gcv.fill_style = FillOpaqueStippled; | |
713 gcv.stipple = ef->emacs_frame.bottom_toolbar_shadow_pixmap; | |
714 flags |= GCStipple | GCFillStyle; | |
715 } | |
716 FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv); | |
717 | |
718 #ifdef HAVE_XPM | |
719 FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) = | |
720 FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f); | |
721 #else | |
722 { | |
723 struct device *d = XDEVICE (f->device); | |
724 Display *dpy = DEVICE_X_DISPLAY (d); | |
725 | |
726 gcv.background = WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)); | |
727 gcv.foreground = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy)); | |
728 gcv.graphics_exposures = False; | |
729 flags = GCForeground | GCBackground | GCGraphicsExposures; | |
730 FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) = | |
731 XtGetGC ((Widget) ef, flags, &gcv); | |
732 } | |
733 #endif | |
734 } | |
735 | |
736 static void | |
737 x_release_frame_toolbar_gcs (struct frame *f) | |
738 { | |
739 Widget ew = (Widget) FRAME_X_TEXT_WIDGET (f); | |
740 XtReleaseGC (ew, FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f)); | |
741 /* If compiled with XPM support, this is a pointer to the same GC as | |
742 FRAME_X_BLANK_BACKGROUND_GC so we need to make sure we don't | |
743 release it twice. */ | |
744 #ifndef HAVE_XPM | |
745 XtReleaseGC (ew, FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f)); | |
746 #endif | |
747 XtReleaseGC (ew, FRAME_X_TOOLBAR_TOP_SHADOW_GC (f)); | |
748 XtReleaseGC (ew, FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f)); | |
749 | |
750 /* Seg fault if we try and use these again. */ | |
751 FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f) = (GC) -1; | |
752 FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) = (GC) -1; | |
753 FRAME_X_TOOLBAR_TOP_SHADOW_GC (f) = (GC) -1; | |
754 FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f) = (GC) -1; | |
755 } | |
756 | |
757 static void | |
758 x_initialize_frame_toolbars (struct frame *f) | |
759 { | |
760 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
761 | |
762 if (ef->emacs_frame.toolbar_shadow_thickness < MINIMUM_SHADOW_THICKNESS) | |
763 { | |
764 XtVaSetValues (FRAME_X_TEXT_WIDGET (f), XtNtoolBarShadowThickness, | |
765 MINIMUM_SHADOW_THICKNESS, 0); | |
766 } | |
767 | |
768 x_initialize_frame_toolbar_gcs (f); | |
769 } | |
770 | |
771 /* This only calls one function but we go ahead and create this in | |
772 case we ever do decide that we need to do more work. */ | |
773 static void | |
774 x_free_frame_toolbars (struct frame *f) | |
775 { | |
776 x_release_frame_toolbar_gcs (f); | |
777 } | |
778 | |
779 | |
780 /************************************************************************/ | |
781 /* initialization */ | |
782 /************************************************************************/ | |
783 | |
784 void | |
785 console_type_create_toolbar_x (void) | |
786 { | |
787 CONSOLE_HAS_METHOD (x, output_frame_toolbars); | |
788 CONSOLE_HAS_METHOD (x, initialize_frame_toolbars); | |
789 CONSOLE_HAS_METHOD (x, free_frame_toolbars); | |
790 CONSOLE_HAS_METHOD (x, output_toolbar_button); | |
791 CONSOLE_HAS_METHOD (x, redraw_exposed_toolbars); | |
792 CONSOLE_HAS_METHOD (x, redraw_frame_toolbars); | |
793 CONSOLE_HAS_METHOD (x, toolbar_size_changed_in_frame); | |
794 CONSOLE_HAS_METHOD (x, toolbar_visible_p_changed_in_frame); | |
795 } |