1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19
20 #include <config.h>
21
22 #ifdef USE_GTK
23 #include <string.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <setjmp.h>
27 #include "lisp.h"
28 #include "xterm.h"
29 #include "blockinput.h"
30 #include "syssignal.h"
31 #include "window.h"
32 #include "gtkutil.h"
33 #include "termhooks.h"
34 #include "keyboard.h"
35 #include "charset.h"
36 #include "coding.h"
37 #include <gdk/gdkkeysyms.h>
38 #include "xsettings.h"
39
40 #ifdef HAVE_XFT
41 #include <X11/Xft/Xft.h>
42 #endif
43
44 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
45 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
46
47
48 #define SSDATA(x) ((char *) SDATA (x))
49
50
51 52 53
54
55 #ifdef HAVE_GTK_MULTIDISPLAY
56
57 58
59
60 static GdkDisplay *gdpy_def;
61
62 63 64
65
66 static void
67 xg_set_screen (w, f)
68 GtkWidget *w;
69 FRAME_PTR f;
70 {
71 if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
72 {
73 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
74 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
75
76 if (GTK_IS_MENU (w))
77 gtk_menu_set_screen (GTK_MENU (w), gscreen);
78 else
79 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
80 }
81 }
82
83
84 #else
85
86 87
88
89 #define xg_set_screen(w, f)
90 #define gdk_xid_table_lookup_for_display(dpy, w) gdk_xid_table_lookup (w)
91 #define gdk_pixmap_foreign_new_for_display(dpy, p) gdk_pixmap_foreign_new (p)
92 #define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c)
93 #define gdk_x11_lookup_xdisplay(dpy) 0
94 #define GdkDisplay void
95
96 #endif
97
98 99 100 101 102 103
104
105 int
106 xg_display_open (display_name, dpy)
107 char *display_name;
108 Display **dpy;
109 {
110 #ifdef HAVE_GTK_MULTIDISPLAY
111 GdkDisplay *gdpy;
112
113 gdpy = gdk_display_open (display_name);
114 if (!gdpy_def && gdpy)
115 {
116 gdpy_def = gdpy;
117 gdk_display_manager_set_default_display (gdk_display_manager_get (),
118 gdpy);
119 }
120
121 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
122 return gdpy != NULL;
123
124 #else
125
126 return -1;
127 #endif
128 }
129
130
131
132
133 void
134 xg_display_close (Display *dpy)
135 {
136 #ifdef HAVE_GTK_MULTIDISPLAY
137 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
138
139 140 141
142 if (gdk_display_get_default () == gdpy)
143 {
144 struct x_display_info *dpyinfo;
145 GdkDisplay *gdpy_new = NULL;
146
147
148 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
149 if (dpyinfo->display != dpy)
150 {
151 gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
152 gdk_display_manager_set_default_display (gdk_display_manager_get (),
153 gdpy_new);
154 break;
155 }
156 gdpy_def = gdpy_new;
157 }
158
159 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
160 161 162
163 g_object_run_dispose (G_OBJECT (gdpy));
164 #else
165
166 gdk_display_close (gdpy);
167 #endif
168 #endif
169 }
170
171
172 173 174
175
176 static widget_value *widget_value_free_list;
177 static int malloc_cpt;
178
179 180 181 182
183
184 widget_value *
185 malloc_widget_value ()
186 {
187 widget_value *wv;
188 if (widget_value_free_list)
189 {
190 wv = widget_value_free_list;
191 widget_value_free_list = wv->free_list;
192 wv->free_list = 0;
193 }
194 else
195 {
196 wv = (widget_value *) xmalloc (sizeof (widget_value));
197 malloc_cpt++;
198 }
199 memset (wv, 0, sizeof (widget_value));
200 return wv;
201 }
202
203 204
205
206 void
207 free_widget_value (wv)
208 widget_value *wv;
209 {
210 if (wv->free_list)
211 abort ();
212
213 if (malloc_cpt > 25)
214 {
215 216
217 xfree (wv);
218 malloc_cpt--;
219 }
220 else
221 {
222 wv->free_list = widget_value_free_list;
223 widget_value_free_list = wv;
224 }
225 }
226
227
228 229
230
231 GdkCursor *
232 xg_create_default_cursor (dpy)
233 Display *dpy;
234 {
235 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
236 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
237 }
238
239
240
241 static GdkPixbuf *
242 xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
243 GdkPixmap *gpix;
244 GdkPixmap *gmask;
245 GdkColormap *cmap;
246 {
247 int width, height;
248 GdkPixbuf *icon_buf, *tmp_buf;
249
250 gdk_drawable_get_size (gpix, &width, &height);
251 tmp_buf = gdk_pixbuf_get_from_drawable (NULL, gpix, cmap,
252 0, 0, 0, 0, width, height);
253 icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
254 g_object_unref (G_OBJECT (tmp_buf));
255
256 if (gmask)
257 {
258 GdkPixbuf *mask_buf = gdk_pixbuf_get_from_drawable (NULL,
259 gmask,
260 NULL,
261 0, 0, 0, 0,
262 width, height);
263 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
264 guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
265 int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
266 int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf);
267 int y;
268
269 for (y = 0; y < height; ++y)
270 {
271 guchar *iconptr, *maskptr;
272 int x;
273
274 iconptr = pixels + y * rowstride;
275 maskptr = mask_pixels + y * mask_rowstride;
276
277 for (x = 0; x < width; ++x)
278 {
279 280
281 if (maskptr[0] == 0)
282 iconptr[3] = 0;
283
284 iconptr += rowstride/width;
285 maskptr += mask_rowstride/width;
286 }
287 }
288
289 g_object_unref (G_OBJECT (mask_buf));
290 }
291
292 return icon_buf;
293 }
294
295 static Lisp_Object
296 file_for_image (image)
297 Lisp_Object image;
298 {
299 Lisp_Object specified_file = Qnil;
300 Lisp_Object tail;
301 extern Lisp_Object QCfile;
302
303 for (tail = XCDR (image);
304 NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
305 tail = XCDR (XCDR (tail)))
306 if (EQ (XCAR (tail), QCfile))
307 specified_file = XCAR (XCDR (tail));
308
309 return specified_file;
310 }
311
312 313 314 315 316 317 318 319 320 321
322
323 static GtkWidget *
324 xg_get_image_for_pixmap (f, img, widget, old_widget)
325 FRAME_PTR f;
326 struct image *img;
327 GtkWidget *widget;
328 GtkImage *old_widget;
329 {
330 GdkPixmap *gpix;
331 GdkPixmap *gmask;
332 GdkDisplay *gdpy;
333 GdkColormap *cmap;
334 GdkPixbuf *icon_buf;
335
336 337 338
339 Lisp_Object specified_file = file_for_image (img->spec);
340 Lisp_Object file;
341
342 343 344
345
346 if (STRINGP (specified_file)
347 && STRINGP (file = x_find_image_file (specified_file)))
348 {
349 if (! old_widget)
350 old_widget = GTK_IMAGE (gtk_image_new_from_file (SSDATA (file)));
351 else
352 gtk_image_set_from_file (old_widget, SSDATA (file));
353
354 return GTK_WIDGET (old_widget);
355 }
356
357 358 359
360
361 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
362 gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
363 gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0;
364
365 366 367 368 369 370 371 372 373
374 cmap = gtk_widget_get_colormap (widget);
375 icon_buf = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap);
376
377 if (! old_widget)
378 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
379 else
380 gtk_image_set_from_pixbuf (old_widget, icon_buf);
381
382 g_object_unref (G_OBJECT (icon_buf));
383
384 g_object_unref (G_OBJECT (gpix));
385 if (gmask) g_object_unref (G_OBJECT (gmask));
386
387 return GTK_WIDGET (old_widget);
388 }
389
390
391 392 393
394
395 static void
396 xg_set_cursor (w, cursor)
397 GtkWidget *w;
398 GdkCursor *cursor;
399 {
400 GList *children = gdk_window_peek_children (w->window);
401
402 gdk_window_set_cursor (w->window, cursor);
403
404 405 406 407
408
409 for ( ; children; children = g_list_next (children))
410 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
411 }
412
413
414
415 static void
416 xg_list_insert (xg_list_node *list, xg_list_node *node)
417 {
418 xg_list_node *list_start = list->next;
419
420 if (list_start) list_start->prev = node;
421 node->next = list_start;
422 node->prev = 0;
423 list->next = node;
424 }
425
426
427
428 static void
429 xg_list_remove (xg_list_node *list, xg_list_node *node)
430 {
431 xg_list_node *list_start = list->next;
432 if (node == list_start)
433 {
434 list->next = node->next;
435 if (list->next) list->next->prev = 0;
436 }
437 else
438 {
439 node->prev->next = node->next;
440 if (node->next) node->next->prev = node->prev;
441 }
442 }
443
444 445 446 447
448
449 static char *
450 get_utf8_string (str)
451 char *str;
452 {
453 char *utf8_str = str;
454
455 if (!str) return NULL;
456
457
458 if (!g_utf8_validate (str, -1, NULL))
459 utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
460
461 if (!utf8_str)
462 {
463
464 size_t nr_bad = 0;
465 gsize bytes_read;
466 gsize bytes_written;
467 unsigned char *p = (unsigned char *)str;
468 char *cp, *up;
469 GError *error = NULL;
470
471 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
472 &bytes_written, &error))
473 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
474 {
475 ++nr_bad;
476 p += bytes_written+1;
477 g_error_free (error);
478 error = NULL;
479 }
480
481 if (error)
482 {
483 g_error_free (error);
484 error = NULL;
485 }
486 if (cp) g_free (cp);
487
488 up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
489 p = (unsigned char *)str;
490
491 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
492 &bytes_written, &error))
493 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
494 {
495 strncpy (up, (char *)p, bytes_written);
496 sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
497 up[bytes_written+4] = '\0';
498 up += bytes_written+4;
499 p += bytes_written+1;
500 g_error_free (error);
501 error = NULL;
502 }
503
504 if (cp)
505 {
506 strcat (utf8_str, cp);
507 g_free (cp);
508 }
509 if (error)
510 {
511 g_error_free (error);
512 error = NULL;
513 }
514 }
515 return utf8_str;
516 }
517
518
519
520 521 522
523
524 525 526 527
528
529 static void
530 xg_set_geometry (f)
531 FRAME_PTR f;
532 {
533 if (f->size_hint_flags & (USPosition | PPosition))
534 {
535 int left = f->left_pos;
536 int xneg = f->size_hint_flags & XNegative;
537 int top = f->top_pos;
538 int yneg = f->size_hint_flags & YNegative;
539 char geom_str[32];
540
541 if (xneg)
542 left = -left;
543 if (yneg)
544 top = -top;
545
546 sprintf (geom_str, "=%dx%d%c%d%c%d",
547 FRAME_PIXEL_WIDTH (f),
548 FRAME_PIXEL_HEIGHT (f),
549 (xneg ? '-' : '+'), left,
550 (yneg ? '-' : '+'), top);
551
552 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
553 geom_str))
554 fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
555 }
556 }
557
558 559
560
561 static void
562 xg_clear_under_internal_border (f)
563 FRAME_PTR f;
564 {
565 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
566 {
567 GtkWidget *wfixed = f->output_data.x->edit_widget;
568 gtk_widget_queue_draw (wfixed);
569 gdk_window_process_all_updates ();
570 x_clear_area (FRAME_X_DISPLAY (f),
571 FRAME_X_WINDOW (f),
572 0, 0,
573 FRAME_PIXEL_WIDTH (f),
574 FRAME_INTERNAL_BORDER_WIDTH (f), 0);
575 x_clear_area (FRAME_X_DISPLAY (f),
576 FRAME_X_WINDOW (f),
577 0, 0,
578 FRAME_INTERNAL_BORDER_WIDTH (f),
579 FRAME_PIXEL_HEIGHT (f), 0);
580 x_clear_area (FRAME_X_DISPLAY (f),
581 FRAME_X_WINDOW (f),
582 0, FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
583 FRAME_PIXEL_WIDTH (f),
584 FRAME_INTERNAL_BORDER_WIDTH (f), 0);
585 x_clear_area (FRAME_X_DISPLAY (f),
586 FRAME_X_WINDOW (f),
587 FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
588 0,
589 FRAME_INTERNAL_BORDER_WIDTH (f),
590 FRAME_PIXEL_HEIGHT (f), 0);
591 }
592 }
593
594 595 596 597 598
599
600 void
601 xg_frame_resized (f, pixelwidth, pixelheight)
602 FRAME_PTR f;
603 int pixelwidth, pixelheight;
604 {
605 int rows, columns;
606
607 if (pixelwidth == -1 && pixelheight == -1)
608 {
609 if (FRAME_GTK_WIDGET (f) && GTK_WIDGET_MAPPED (FRAME_GTK_WIDGET (f)))
610 gdk_window_get_geometry (FRAME_GTK_WIDGET (f)->window, 0, 0,
611 &pixelwidth, &pixelheight, 0);
612 else return;
613 }
614
615
616 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
617 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
618
619 if (columns != FRAME_COLS (f)
620 || rows != FRAME_LINES (f)
621 || pixelwidth != FRAME_PIXEL_WIDTH (f)
622 || pixelheight != FRAME_PIXEL_HEIGHT (f))
623 {
624 FRAME_PIXEL_WIDTH (f) = pixelwidth;
625 FRAME_PIXEL_HEIGHT (f) = pixelheight;
626
627 xg_clear_under_internal_border (f);
628 change_frame_size (f, rows, columns, 0, 1, 0);
629 SET_FRAME_GARBAGED (f);
630 cancel_mouse_face (f);
631 }
632 }
633
634 635
636
637 void
638 xg_frame_set_char_size (f, cols, rows)
639 FRAME_PTR f;
640 int cols;
641 int rows;
642 {
643 int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
644 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
645 int pixelwidth;
646
647 if (FRAME_PIXEL_HEIGHT (f) == 0)
648 return;
649
650 651 652 653 654
655 f->scroll_bar_actual_width
656 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
657
658 compute_fringe_widths (f, 0);
659
660 661
662 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
663
664
665
666 xg_clear_under_internal_border (f);
667
668 669
670 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
671 pixelwidth, pixelheight);
672 x_wm_set_size_hint (f, 0, 0);
673
674 SET_FRAME_GARBAGED (f);
675 cancel_mouse_face (f);
676
677 678 679 680 681 682 683
684 if (f->async_visible)
685 {
686
687 (void)gtk_events_pending ();
688 gdk_flush ();
689 x_wait_for_event (f, ConfigureNotify);
690 }
691 else
692 {
693 change_frame_size (f, rows, cols, 0, 1, 0);
694 FRAME_PIXEL_WIDTH (f) = pixelwidth;
695 FRAME_PIXEL_HEIGHT (f) = pixelheight;
696 }
697 }
698
699 700
701
702 static void
703 xg_height_changed (f)
704 FRAME_PTR f;
705 {
706 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
707 FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f));
708 f->output_data.x->hint_flags = 0;
709 x_wm_set_size_hint (f, 0, 0);
710 }
711
712 713 714 715 716
717
718 GtkWidget *
719 xg_win_to_widget (dpy, wdesc)
720 Display *dpy;
721 Window wdesc;
722 {
723 gpointer gdkwin;
724 GtkWidget *gwdesc = 0;
725
726 BLOCK_INPUT;
727
728 gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
729 wdesc);
730 if (gdkwin)
731 {
732 GdkEvent event;
733 event.any.window = gdkwin;
734 gwdesc = gtk_get_event_widget (&event);
735 }
736
737 UNBLOCK_INPUT;
738 return gwdesc;
739 }
740
741 742
743
744 static void
745 xg_pix_to_gcolor (w, pixel, c)
746 GtkWidget *w;
747 unsigned long pixel;
748 GdkColor *c;
749 {
750 GdkColormap *map = gtk_widget_get_colormap (w);
751 gdk_colormap_query_color (map, pixel, c);
752 }
753
754 755
756
757 int
758 xg_create_frame_widgets (f)
759 FRAME_PTR f;
760 {
761 GtkWidget *wtop;
762 GtkWidget *wvbox;
763 GtkWidget *wfixed;
764 GdkColor bg;
765 GtkRcStyle *style;
766 char *title = 0;
767
768 BLOCK_INPUT;
769
770 if (FRAME_X_EMBEDDED_P (f))
771 wtop = gtk_plug_new (f->output_data.x->parent_desc);
772 else
773 wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
774
775 xg_set_screen (wtop, f);
776
777 wvbox = gtk_vbox_new (FALSE, 0);
778 wfixed = gtk_fixed_new ();
779
780 if (! wtop || ! wvbox || ! wfixed)
781 {
782 if (wtop) gtk_widget_destroy (wtop);
783 if (wvbox) gtk_widget_destroy (wvbox);
784 if (wfixed) gtk_widget_destroy (wfixed);
785
786 UNBLOCK_INPUT;
787 return 0;
788 }
789
790
791 gtk_widget_set_name (wtop, EMACS_CLASS);
792 gtk_widget_set_name (wvbox, "pane");
793 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
794
795
796 if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title));
797 else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name));
798
799 if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
800
801 FRAME_GTK_OUTER_WIDGET (f) = wtop;
802 FRAME_GTK_WIDGET (f) = wfixed;
803 f->output_data.x->vbox_widget = wvbox;
804
805 gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
806
807 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
808 gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
809
810 if (FRAME_EXTERNAL_TOOL_BAR (f))
811 update_frame_tool_bar (f);
812
813 814 815 816 817
818 gtk_widget_set_double_buffered (wfixed, FALSE);
819
820 gtk_window_set_wmclass (GTK_WINDOW (wtop),
821 SSDATA (Vx_resource_name),
822 SSDATA (Vx_resource_class));
823
824 825
826 g_signal_connect (G_OBJECT (wtop), "delete-event",
827 G_CALLBACK (gtk_true), 0);
828
829 830 831
832 xg_set_geometry (f);
833 f->win_gravity
834 = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
835
836 gtk_widget_add_events (wfixed,
837 GDK_POINTER_MOTION_MASK
838 | GDK_EXPOSURE_MASK
839 | GDK_BUTTON_PRESS_MASK
840 | GDK_BUTTON_RELEASE_MASK
841 | GDK_KEY_PRESS_MASK
842 | GDK_ENTER_NOTIFY_MASK
843 | GDK_LEAVE_NOTIFY_MASK
844 | GDK_FOCUS_CHANGE_MASK
845 | GDK_STRUCTURE_MASK
846 | GDK_VISIBILITY_NOTIFY_MASK);
847
848 849
850 gtk_widget_realize (wfixed);
851 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
852
853 854
855 xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg);
856 gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg);
857
858 859 860
861 style = gtk_widget_get_modifier_style (wfixed);
862
863
864 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
865 gtk_widget_modify_style (wfixed, style);
866
867
868 869 870 871
872
873 UNBLOCK_INPUT;
874
875 return 1;
876 }
877
878 879 880 881 882
883
884 void
885 x_wm_set_size_hint (f, flags, user_position)
886 FRAME_PTR f;
887 long flags;
888 int user_position;
889 {
890 891
892 GdkGeometry size_hints;
893 gint hint_flags = 0;
894 int base_width, base_height;
895 int min_rows = 0, min_cols = 0;
896 int win_gravity = f->win_gravity;
897
898 899 900
901 if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
902 return;
903
904 if (flags)
905 {
906 memset (&size_hints, 0, sizeof (size_hints));
907 f->output_data.x->size_hints = size_hints;
908 f->output_data.x->hint_flags = hint_flags;
909 }
910 else
911 flags = f->size_hint_flags;
912
913 size_hints = f->output_data.x->size_hints;
914 hint_flags = f->output_data.x->hint_flags;
915
916 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
917 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
918 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
919
920 hint_flags |= GDK_HINT_BASE_SIZE;
921 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
922 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
923 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
924
925 check_frame_size (f, &min_rows, &min_cols);
926
927 size_hints.base_width = base_width;
928 size_hints.base_height = base_height;
929 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
930 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
931
932 933
934 hint_flags |= GDK_HINT_WIN_GRAVITY;
935 size_hints.win_gravity = 0;
936 if (win_gravity == NorthWestGravity)
937 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
938 else if (win_gravity == NorthGravity)
939 size_hints.win_gravity = GDK_GRAVITY_NORTH;
940 else if (win_gravity == NorthEastGravity)
941 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
942 else if (win_gravity == WestGravity)
943 size_hints.win_gravity = GDK_GRAVITY_WEST;
944 else if (win_gravity == CenterGravity)
945 size_hints.win_gravity = GDK_GRAVITY_CENTER;
946 else if (win_gravity == EastGravity)
947 size_hints.win_gravity = GDK_GRAVITY_EAST;
948 else if (win_gravity == SouthWestGravity)
949 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
950 else if (win_gravity == SouthGravity)
951 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
952 else if (win_gravity == SouthEastGravity)
953 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
954 else if (win_gravity == StaticGravity)
955 size_hints.win_gravity = GDK_GRAVITY_STATIC;
956
957 if (user_position)
958 {
959 hint_flags &= ~GDK_HINT_POS;
960 hint_flags |= GDK_HINT_USER_POS;
961 }
962
963 if (hint_flags != f->output_data.x->hint_flags
964 || memcmp (&size_hints,
965 &f->output_data.x->size_hints,
966 sizeof (size_hints)) != 0)
967 {
968 BLOCK_INPUT;
969 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
970 NULL, &size_hints, hint_flags);
971 f->output_data.x->size_hints = size_hints;
972 f->output_data.x->hint_flags = hint_flags;
973 UNBLOCK_INPUT;
974 }
975 }
976
977 978 979 980 981
982
983 void
984 xg_set_background_color (f, bg)
985 FRAME_PTR f;
986 unsigned long bg;
987 {
988 if (FRAME_GTK_WIDGET (f))
989 {
990 GdkColor gdk_bg;
991
992 BLOCK_INPUT;
993 xg_pix_to_gcolor (FRAME_GTK_WIDGET (f), bg, &gdk_bg);
994 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &gdk_bg);
995 UNBLOCK_INPUT;
996 }
997 }
998
999
1000 1001
1002
1003 void
1004 xg_set_frame_icon (f, icon_pixmap, icon_mask)
1005 FRAME_PTR f;
1006 Pixmap icon_pixmap;
1007 Pixmap icon_mask;
1008 {
1009 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
1010 GdkPixmap *gpix = gdk_pixmap_foreign_new_for_display (gdpy, icon_pixmap);
1011 GdkPixmap *gmask = gdk_pixmap_foreign_new_for_display (gdpy, icon_mask);
1012 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, NULL);
1013
1014 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
1015 }
1016
1017
1018
1019 1020 1021
1022 1023
1024
1025 static char *
1026 get_dialog_title (char key)
1027 {
1028 char *title = "";
1029
1030 switch (key) {
1031 case 'E': case 'e':
1032 title = "Error";
1033 break;
1034
1035 case 'I': case 'i':
1036 title = "Information";
1037 break;
1038
1039 case 'L': case 'l':
1040 title = "Prompt";
1041 break;
1042
1043 case 'P': case 'p':
1044 title = "Prompt";
1045 break;
1046
1047 case 'Q': case 'q':
1048 title = "Question";
1049 break;
1050 }
1051
1052 return title;
1053 }
1054
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
1065
1066 static gboolean
1067 dialog_delete_callback (w, event, user_data)
1068 GtkWidget *w;
1069 GdkEvent *event;
1070 gpointer user_data;
1071 {
1072 gtk_widget_unmap (w);
1073 return TRUE;
1074 }
1075
1076 1077 1078 1079 1080 1081
1082
1083 static GtkWidget *
1084 create_dialog (wv, select_cb, deactivate_cb)
1085 widget_value *wv;
1086 GCallback select_cb;
1087 GCallback deactivate_cb;
1088 {
1089 char *title = get_dialog_title (wv->name[0]);
1090 int total_buttons = wv->name[1] - '0';
1091 int right_buttons = wv->name[4] - '0';
1092 int left_buttons;
1093 int button_nr = 0;
1094 int button_spacing = 10;
1095 GtkWidget *wdialog = gtk_dialog_new ();
1096 widget_value *item;
1097 GtkBox *cur_box;
1098 GtkWidget *wvbox;
1099 GtkWidget *whbox_up;
1100 GtkWidget *whbox_down;
1101
1102 1103
1104 int make_two_rows = total_buttons > 4;
1105
1106 if (right_buttons == 0) right_buttons = total_buttons/2;
1107 left_buttons = total_buttons - right_buttons;
1108
1109 gtk_window_set_title (GTK_WINDOW (wdialog), title);
1110 gtk_widget_set_name (wdialog, "emacs-dialog");
1111
1112 cur_box = GTK_BOX (GTK_DIALOG (wdialog)->action_area);
1113
1114 if (make_two_rows)
1115 {
1116 wvbox = gtk_vbox_new (TRUE, button_spacing);
1117 whbox_up = gtk_hbox_new (FALSE, 0);
1118 whbox_down = gtk_hbox_new (FALSE, 0);
1119
1120 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
1121 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
1122 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
1123
1124 cur_box = GTK_BOX (whbox_up);
1125 }
1126
1127 g_signal_connect (G_OBJECT (wdialog), "delete-event",
1128 G_CALLBACK (dialog_delete_callback), 0);
1129
1130 if (deactivate_cb)
1131 {
1132 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
1133 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
1134 }
1135
1136 for (item = wv->contents; item; item = item->next)
1137 {
1138 char *utf8_label = get_utf8_string (item->value);
1139 GtkWidget *w;
1140 GtkRequisition req;
1141
1142 if (item->name && strcmp (item->name, "message") == 0)
1143 {
1144
1145 w = gtk_label_new (utf8_label);
1146 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1147 gtk_label_new (""),
1148 FALSE, FALSE, 0);
1149 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox), w,
1150 TRUE, TRUE, 0);
1151 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
1152
1153 1154
1155 gtk_widget_realize (w);
1156 gtk_widget_size_request (w, &req);
1157 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1158 req.height);
1159 if (item->value && strlen (item->value) > 0)
1160 button_spacing = 2*req.width/strlen (item->value);
1161 }
1162 else
1163 {
1164
1165 w = gtk_button_new_with_label (utf8_label);
1166 if (! item->enabled)
1167 gtk_widget_set_sensitive (w, FALSE);
1168 if (select_cb)
1169 g_signal_connect (G_OBJECT (w), "clicked",
1170 select_cb, item->call_data);
1171
1172 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
1173 if (++button_nr == left_buttons)
1174 {
1175 if (make_two_rows)
1176 cur_box = GTK_BOX (whbox_down);
1177 else
1178 gtk_box_pack_start (cur_box,
1179 gtk_label_new (""),
1180 TRUE, TRUE,
1181 button_spacing);
1182 }
1183 }
1184
1185 if (utf8_label && utf8_label != item->value)
1186 g_free (utf8_label);
1187 }
1188
1189 return wdialog;
1190 }
1191
1192 struct xg_dialog_data
1193 {
1194 GMainLoop *loop;
1195 int response;
1196 GtkWidget *w;
1197 guint timerid;
1198 };
1199
1200 1201 1202
1203
1204 static void
1205 xg_dialog_response_cb (w,
1206 response,
1207 user_data)
1208 GtkDialog *w;
1209 gint response;
1210 gpointer user_data;
1211 {
1212 struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
1213 dd->response = response;
1214 g_main_loop_quit (dd->loop);
1215 }
1216
1217
1218
1219
1220 static Lisp_Object
1221 pop_down_dialog (arg)
1222 Lisp_Object arg;
1223 {
1224 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1225 struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
1226
1227 BLOCK_INPUT;
1228 if (dd->w) gtk_widget_destroy (dd->w);
1229 if (dd->timerid != 0) g_source_remove (dd->timerid);
1230
1231 g_main_loop_quit (dd->loop);
1232 g_main_loop_unref (dd->loop);
1233
1234 UNBLOCK_INPUT;
1235
1236 return Qnil;
1237 }
1238
1239 1240
1241
1242 static gboolean
1243 xg_maybe_add_timer (data)
1244 gpointer data;
1245 {
1246 struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
1247 EMACS_TIME next_time = timer_check (1);
1248 long secs = EMACS_SECS (next_time);
1249 long usecs = EMACS_USECS (next_time);
1250
1251 dd->timerid = 0;
1252
1253 if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
1254 {
1255 dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
1256 xg_maybe_add_timer,
1257 dd);
1258 }
1259 return FALSE;
1260 }
1261
1262
1263 1264 1265
1266
1267 static int
1268 xg_dialog_run (f, w)
1269 FRAME_PTR f;
1270 GtkWidget *w;
1271
1272 {
1273 int count = SPECPDL_INDEX ();
1274 struct xg_dialog_data dd;
1275
1276 xg_set_screen (w, f);
1277 gtk_window_set_transient_for (GTK_WINDOW (w),
1278 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1279 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1280 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1281
1282 dd.loop = g_main_loop_new (NULL, FALSE);
1283 dd.response = GTK_RESPONSE_CANCEL;
1284 dd.w = w;
1285 dd.timerid = 0;
1286
1287 g_signal_connect (G_OBJECT (w),
1288 "response",
1289 G_CALLBACK (xg_dialog_response_cb),
1290 &dd);
1291
1292 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1293 gtk_widget_show (w);
1294
1295 record_unwind_protect (pop_down_dialog, make_save_value (&dd, 0));
1296
1297 (void) xg_maybe_add_timer (&dd);
1298 g_main_loop_run (dd.loop);
1299
1300 dd.w = 0;
1301 unbind_to (count, Qnil);
1302
1303 return dd.response;
1304 }
1305
1306
1307 1308 1309
1310 1311
1312
1313 int
1314 xg_uses_old_file_dialog ()
1315 {
1316 #ifdef HAVE_GTK_FILE_BOTH
1317 extern int x_gtk_use_old_file_dialog;
1318 return x_gtk_use_old_file_dialog;
1319 #else
1320
1321 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1322 return 1;
1323 #else
1324 return 0;
1325 #endif
1326
1327 #endif
1328 }
1329
1330
1331 typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
1332
1333 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1334
1335 1336
1337
1338 static char *
1339 xg_get_file_name_from_chooser (w)
1340 GtkWidget *w;
1341 {
1342 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
1343 }
1344
1345 1346
1347
1348 static void
1349 xg_toggle_visibility_cb (widget, data)
1350 GtkWidget *widget;
1351 gpointer data;
1352 {
1353 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
1354 gboolean visible;
1355 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
1356 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
1357 }
1358
1359
1360 1361 1362 1363 1364
1365
1366 static void
1367 xg_toggle_notify_cb (gobject, arg1, user_data)
1368 GObject *gobject;
1369 GParamSpec *arg1;
1370 gpointer user_data;
1371 {
1372 extern int x_gtk_show_hidden_files;
1373
1374 if (strcmp (arg1->name, "show-hidden") == 0)
1375 {
1376 GtkWidget *wtoggle = GTK_WIDGET (user_data);
1377 gboolean visible, toggle_on;
1378
1379 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
1380 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
1381
1382 if (!!visible != !!toggle_on)
1383 {
1384 g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
1385 G_CALLBACK (xg_toggle_visibility_cb),
1386 gobject);
1387 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
1388 g_signal_handlers_unblock_by_func
1389 (G_OBJECT (wtoggle),
1390 G_CALLBACK (xg_toggle_visibility_cb),
1391 gobject);
1392 }
1393 x_gtk_show_hidden_files = visible;
1394 }
1395 }
1396
1397 1398 1399 1400 1401 1402 1403 1404 1405
1406
1407 static GtkWidget *
1408 xg_get_file_with_chooser (f, prompt, default_filename,
1409 mustmatch_p, only_dir_p, func)
1410 FRAME_PTR f;
1411 char *prompt;
1412 char *default_filename;
1413 int mustmatch_p, only_dir_p;
1414 xg_get_file_func *func;
1415 {
1416 char message[1024];
1417
1418 GtkWidget *filewin, *wtoggle, *wbox, *wmessage;
1419 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
1420 GtkFileChooserAction action = (mustmatch_p ?
1421 GTK_FILE_CHOOSER_ACTION_OPEN :
1422 GTK_FILE_CHOOSER_ACTION_SAVE);
1423 extern int x_gtk_show_hidden_files;
1424 extern int x_gtk_file_dialog_help_text;
1425
1426
1427 if (only_dir_p)
1428 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1429
1430 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
1431 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1432 (mustmatch_p || only_dir_p ?
1433 GTK_STOCK_OPEN : GTK_STOCK_OK),
1434 GTK_RESPONSE_OK,
1435 NULL);
1436 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
1437
1438 wbox = gtk_vbox_new (FALSE, 0);
1439 gtk_widget_show (wbox);
1440 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
1441
1442 if (x_gtk_show_hidden_files)
1443 {
1444 g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
1445 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
1446 }
1447 gtk_widget_show (wtoggle);
1448 g_signal_connect (G_OBJECT (wtoggle), "clicked",
1449 G_CALLBACK (xg_toggle_visibility_cb), filewin);
1450 g_signal_connect (G_OBJECT (filewin), "notify",
1451 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
1452
1453 if (x_gtk_file_dialog_help_text)
1454 {
1455 message[0] = '\0';
1456 1457
1458 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
1459 strcat (message, "\nType C-l to display a file name text entry box.\n");
1460 strcat (message, "\nIf you don't like this file selector, use the "
1461 "corresponding\nkey binding or customize "
1462 "use-file-dialog to turn it off.");
1463
1464 wmessage = gtk_label_new (message);
1465 gtk_widget_show (wmessage);
1466 }
1467
1468 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
1469 if (x_gtk_file_dialog_help_text)
1470 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
1471 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
1472
1473 if (default_filename)
1474 {
1475 Lisp_Object file;
1476 struct gcpro gcpro1;
1477 char *utf8_filename;
1478 GCPRO1 (file);
1479
1480 file = build_string (default_filename);
1481
1482 1483
1484 if (default_filename[0] != '/')
1485 file = Fexpand_file_name (file, Qnil);
1486
1487 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
1488 if (! NILP (Ffile_directory_p (file)))
1489 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
1490 utf8_filename);
1491 else
1492 {
1493 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
1494 utf8_filename);
1495 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
1496 {
1497 char *cp = strrchr (utf8_filename, '/');
1498 if (cp) ++cp;
1499 else cp = utf8_filename;
1500 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
1501 }
1502 }
1503
1504 UNGCPRO;
1505 }
1506
1507 *func = xg_get_file_name_from_chooser;
1508 return filewin;
1509 }
1510 #endif
1511
1512 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1513
1514 1515
1516
1517 static char *
1518 xg_get_file_name_from_selector (w)
1519 GtkWidget *w;
1520 {
1521 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
1522 return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
1523 }
1524
1525 1526 1527 1528 1529 1530 1531 1532 1533
1534
1535 static GtkWidget *
1536 xg_get_file_with_selection (f, prompt, default_filename,
1537 mustmatch_p, only_dir_p, func)
1538 FRAME_PTR f;
1539 char *prompt;
1540 char *default_filename;
1541 int mustmatch_p, only_dir_p;
1542 xg_get_file_func *func;
1543 {
1544 GtkWidget *filewin;
1545 GtkFileSelection *filesel;
1546
1547 filewin = gtk_file_selection_new (prompt);
1548 filesel = GTK_FILE_SELECTION (filewin);
1549
1550 if (default_filename)
1551 gtk_file_selection_set_filename (filesel, default_filename);
1552
1553 if (mustmatch_p)
1554 {
1555
1556 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
1557 gtk_file_selection_hide_fileop_buttons (filesel);
1558 }
1559
1560 *func = xg_get_file_name_from_selector;
1561
1562 return filewin;
1563 }
1564 #endif
1565
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
1578
1579 char *
1580 xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1581 FRAME_PTR f;
1582 char *prompt;
1583 char *default_filename;
1584 int mustmatch_p, only_dir_p;
1585 {
1586 GtkWidget *w = 0;
1587 char *fn = 0;
1588 int filesel_done = 0;
1589 xg_get_file_func func;
1590
1591 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1592 1593 1594
1595 sigblock (sigmask (__SIGRTMIN));
1596 #endif
1597
1598 #ifdef HAVE_GTK_FILE_BOTH
1599
1600 if (xg_uses_old_file_dialog ())
1601 w = xg_get_file_with_selection (f, prompt, default_filename,
1602 mustmatch_p, only_dir_p, &func);
1603 else
1604 w = xg_get_file_with_chooser (f, prompt, default_filename,
1605 mustmatch_p, only_dir_p, &func);
1606
1607 #else
1608
1609 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1610 w = xg_get_file_with_selection (f, prompt, default_filename,
1611 mustmatch_p, only_dir_p, &func);
1612 #endif
1613 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1614 w = xg_get_file_with_chooser (f, prompt, default_filename,
1615 mustmatch_p, only_dir_p, &func);
1616 #endif
1617
1618 #endif
1619
1620 gtk_widget_set_name (w, "emacs-filedialog");
1621
1622 filesel_done = xg_dialog_run (f, w);
1623
1624 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1625 sigunblock (sigmask (__SIGRTMIN));
1626 #endif
1627
1628 if (filesel_done == GTK_RESPONSE_OK)
1629 fn = (*func) (w);
1630
1631 gtk_widget_destroy (w);
1632 return fn;
1633 }
1634
1635 #ifdef HAVE_FREETYPE
1636 1637 1638 1639 1640 1641 1642 1643
1644
1645 char *
1646 xg_get_font_name (f, default_name)
1647 FRAME_PTR f;
1648 char *default_name;
1649 {
1650 GtkWidget *w;
1651 char *fontname = NULL;
1652 int done = 0;
1653
1654 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1655 sigblock (sigmask (__SIGRTMIN));
1656 #endif
1657
1658 w = gtk_font_selection_dialog_new ("Pick a font");
1659 if (!default_name)
1660 default_name = "Monospace 10";
1661 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1662 default_name);
1663
1664 gtk_widget_set_name (w, "emacs-fontdialog");
1665
1666 done = xg_dialog_run (f, w);
1667
1668 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1669 sigunblock (sigmask (__SIGRTMIN));
1670 #endif
1671
1672 if (done == GTK_RESPONSE_OK)
1673 fontname = gtk_font_selection_dialog_get_font_name
1674 (GTK_FONT_SELECTION_DIALOG (w));
1675
1676 gtk_widget_destroy (w);
1677 return fontname;
1678 }
1679 #endif
1680
1681
1682
1683 1684 1685
1686
1687 1688 1689
1690
1691 #define MENU_ITEM_NAME "emacs-menuitem"
1692
1693
1694 1695
1696 static xg_list_node xg_menu_cb_list;
1697
1698 1699
1700 static xg_list_node xg_menu_item_cb_list;
1701
1702 1703 1704 1705 1706 1707 1708 1709 1710
1711
1712 static xg_menu_cb_data *
1713 make_cl_data (cl_data, f, highlight_cb)
1714 xg_menu_cb_data *cl_data;
1715 FRAME_PTR f;
1716 GCallback highlight_cb;
1717 {
1718 if (! cl_data)
1719 {
1720 cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
1721 cl_data->f = f;
1722 cl_data->menu_bar_vector = f->menu_bar_vector;
1723 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1724 cl_data->highlight_cb = highlight_cb;
1725 cl_data->ref_count = 0;
1726
1727 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
1728 }
1729
1730 cl_data->ref_count++;
1731
1732 return cl_data;
1733 }
1734
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
1745
1746 static void
1747 update_cl_data (cl_data, f, highlight_cb)
1748 xg_menu_cb_data *cl_data;
1749 FRAME_PTR f;
1750 GCallback highlight_cb;
1751 {
1752 if (cl_data)
1753 {
1754 cl_data->f = f;
1755 cl_data->menu_bar_vector = f->menu_bar_vector;
1756 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1757 cl_data->highlight_cb = highlight_cb;
1758 }
1759 }
1760
1761 1762
1763
1764 static void
1765 unref_cl_data (cl_data)
1766 xg_menu_cb_data *cl_data;
1767 {
1768 if (cl_data && cl_data->ref_count > 0)
1769 {
1770 cl_data->ref_count--;
1771 if (cl_data->ref_count == 0)
1772 {
1773 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
1774 xfree (cl_data);
1775 }
1776 }
1777 }
1778
1779
1780
1781 void
1782 xg_mark_data ()
1783 {
1784 xg_list_node *iter;
1785
1786 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
1787 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
1788
1789 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
1790 {
1791 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
1792
1793 if (! NILP (cb_data->help))
1794 mark_object (cb_data->help);
1795 }
1796 }
1797
1798
1799 1800 1801
1802
1803 static void
1804 menuitem_destroy_callback (w, client_data)
1805 GtkWidget *w;
1806 gpointer client_data;
1807 {
1808 if (client_data)
1809 {
1810 xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
1811 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
1812 xfree (data);
1813 }
1814 }
1815
1816 1817 1818 1819 1820 1821
1822
1823 static gboolean
1824 menuitem_highlight_callback (w, event, client_data)
1825 GtkWidget *w;
1826 GdkEventCrossing *event;
1827 gpointer client_data;
1828 {
1829 GdkEvent ev;
1830 GtkWidget *subwidget;
1831 xg_menu_item_cb_data *data;
1832
1833 ev.crossing = *event;
1834 subwidget = gtk_get_event_widget (&ev);
1835 data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
1836 XG_ITEM_DATA);
1837 if (data)
1838 {
1839 if (! NILP (data->help) && data->cl_data->highlight_cb)
1840 {
1841 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
1842 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
1843 (*func) (subwidget, call_data);
1844 }
1845 }
1846
1847 return FALSE;
1848 }
1849
1850 1851 1852
1853
1854 static void
1855 menu_destroy_callback (w, client_data)
1856 GtkWidget *w;
1857 gpointer client_data;
1858 {
1859 unref_cl_data ((xg_menu_cb_data*) client_data);
1860 }
1861
1862 1863 1864 1865
1866
1867 static GtkWidget *
1868 make_widget_for_menu_item (utf8_label, utf8_key)
1869 char *utf8_label;
1870 char *utf8_key;
1871 {
1872 GtkWidget *wlbl;
1873 GtkWidget *wkey;
1874 GtkWidget *wbox;
1875
1876 wbox = gtk_hbox_new (FALSE, 0);
1877 wlbl = gtk_label_new (utf8_label);
1878 wkey = gtk_label_new (utf8_key);
1879
1880 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
1881 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
1882
1883 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
1884 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
1885
1886 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
1887 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
1888 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
1889
1890 return wbox;
1891 }
1892
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
1906
1907 static GtkWidget *
1908 make_menu_item (utf8_label, utf8_key, item, group)
1909 char *utf8_label;
1910 char *utf8_key;
1911 widget_value *item;
1912 GSList **group;
1913 {
1914 GtkWidget *w;
1915 GtkWidget *wtoadd = 0;
1916
1917 1918 1919 1920
1921 if (! utf8_label) utf8_label = " ";
1922
1923 if (utf8_key)
1924 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
1925
1926 if (item->button_type == BUTTON_TYPE_TOGGLE)
1927 {
1928 *group = NULL;
1929 if (utf8_key) w = gtk_check_menu_item_new ();
1930 else w = gtk_check_menu_item_new_with_label (utf8_label);
1931 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
1932 }
1933 else if (item->button_type == BUTTON_TYPE_RADIO)
1934 {
1935 if (utf8_key) w = gtk_radio_menu_item_new (*group);
1936 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
1937 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
1938 if (item->selected)
1939 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
1940 }
1941 else
1942 {
1943 *group = NULL;
1944 if (utf8_key) w = gtk_menu_item_new ();
1945 else w = gtk_menu_item_new_with_label (utf8_label);
1946 }
1947
1948 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
1949 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
1950
1951 return w;
1952 }
1953
1954 1955
1956
1957 static const char* separator_names[] = {
1958 "space",
1959 "no-line",
1960 "single-line",
1961 "double-line",
1962 "single-dashed-line",
1963 "double-dashed-line",
1964 "shadow-etched-in",
1965 "shadow-etched-out",
1966 "shadow-etched-in-dash",
1967 "shadow-etched-out-dash",
1968 "shadow-double-etched-in",
1969 "shadow-double-etched-out",
1970 "shadow-double-etched-in-dash",
1971 "shadow-double-etched-out-dash",
1972 0,
1973 };
1974
1975 static int
1976 xg_separator_p (char *label)
1977 {
1978 if (! label) return 0;
1979 else if (strlen (label) > 3
1980 && strncmp (label, "--", 2) == 0
1981 && label[2] != '-')
1982 {
1983 int i;
1984
1985 label += 2;
1986 for (i = 0; separator_names[i]; ++i)
1987 if (strcmp (label, separator_names[i]) == 0)
1988 return 1;
1989 }
1990 else
1991 {
1992 1993
1994 while (*label == '-')
1995 ++label;
1996 if (*label == 0) return 1;
1997 }
1998
1999 return 0;
2000 }
2001
2002 static int xg_detached_menus;
2003
2004
2005
2006 int
2007 xg_have_tear_offs ()
2008 {
2009 return xg_detached_menus > 0;
2010 }
2011
2012 2013 2014 2015
2016
2017 static void
2018 tearoff_remove (widget, client_data)
2019 GtkWidget *widget;
2020 gpointer client_data;
2021 {
2022 if (xg_detached_menus > 0) --xg_detached_menus;
2023 }
2024
2025 2026 2027 2028
2029
2030 static void
2031 tearoff_activate (widget, client_data)
2032 GtkWidget *widget;
2033 gpointer client_data;
2034 {
2035 GtkWidget *menu = gtk_widget_get_parent (widget);
2036 if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
2037 {
2038 ++xg_detached_menus;
2039 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
2040 "destroy",
2041 G_CALLBACK (tearoff_remove), 0);
2042 }
2043 }
2044
2045
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
2059
2060 static GtkWidget *
2061 xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
2062 widget_value *item;
2063 FRAME_PTR f;
2064 GCallback select_cb;
2065 GCallback highlight_cb;
2066 xg_menu_cb_data *cl_data;
2067 GSList **group;
2068 {
2069 char *utf8_label;
2070 char *utf8_key;
2071 GtkWidget *w;
2072 xg_menu_item_cb_data *cb_data;
2073
2074 utf8_label = get_utf8_string (item->name);
2075 utf8_key = get_utf8_string (item->key);
2076
2077 w = make_menu_item (utf8_label, utf8_key, item, group);
2078
2079 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2080 if (utf8_key && utf8_key != item->key) g_free (utf8_key);
2081
2082 cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
2083
2084 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
2085
2086 cb_data->select_id = 0;
2087 cb_data->help = item->help;
2088 cb_data->cl_data = cl_data;
2089 cb_data->call_data = item->call_data;
2090
2091 g_signal_connect (G_OBJECT (w),
2092 "destroy",
2093 G_CALLBACK (menuitem_destroy_callback),
2094 cb_data);
2095
2096
2097 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
2098
2099
2100 if (item->call_data && ! item->contents)
2101 {
2102 if (select_cb)
2103 cb_data->select_id
2104 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
2105 }
2106
2107 return w;
2108 }
2109
2110 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
2111 GCallback, GCallback, int, int, int,
2112 GtkWidget *, xg_menu_cb_data *, char *));
2113
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
2135
2136 static GtkWidget *
2137 create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
2138 pop_up_p, menu_bar_p, add_tearoff_p, topmenu, cl_data, name)
2139 widget_value *data;
2140 FRAME_PTR f;
2141 GCallback select_cb;
2142 GCallback deactivate_cb;
2143 GCallback highlight_cb;
2144 int pop_up_p;
2145 int menu_bar_p;
2146 int add_tearoff_p;
2147 GtkWidget *topmenu;
2148 xg_menu_cb_data *cl_data;
2149 char *name;
2150 {
2151 widget_value *item;
2152 GtkWidget *wmenu = topmenu;
2153 GSList *group = NULL;
2154
2155 if (! topmenu)
2156 {
2157 if (! menu_bar_p)
2158 {
2159 wmenu = gtk_menu_new ();
2160 xg_set_screen (wmenu, f);
2161 2162 2163
2164 g_signal_connect (G_OBJECT (wmenu),
2165 "enter-notify-event",
2166 G_CALLBACK (menuitem_highlight_callback),
2167 NULL);
2168 g_signal_connect (G_OBJECT (wmenu),
2169 "leave-notify-event",
2170 G_CALLBACK (menuitem_highlight_callback),
2171 NULL);
2172 }
2173 else
2174 {
2175 wmenu = gtk_menu_bar_new ();
2176 2177 2178 2179
2180 gtk_widget_set_size_request (wmenu, 1, -1);
2181 }
2182
2183
2184 cl_data = make_cl_data (cl_data, f, highlight_cb);
2185 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
2186 g_signal_connect (G_OBJECT (wmenu), "destroy",
2187 G_CALLBACK (menu_destroy_callback), cl_data);
2188
2189 if (name)
2190 gtk_widget_set_name (wmenu, name);
2191
2192 if (deactivate_cb)
2193 g_signal_connect (G_OBJECT (wmenu),
2194 "selection-done", deactivate_cb, 0);
2195 }
2196
2197 if (! menu_bar_p && add_tearoff_p)
2198 {
2199 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2200 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
2201
2202 g_signal_connect (G_OBJECT (tearoff), "activate",
2203 G_CALLBACK (tearoff_activate), 0);
2204 }
2205
2206 for (item = data; item; item = item->next)
2207 {
2208 GtkWidget *w;
2209
2210 if (pop_up_p && !item->contents && !item->call_data
2211 && !xg_separator_p (item->name))
2212 {
2213 char *utf8_label;
2214 2215
2216 group = NULL;
2217 utf8_label = get_utf8_string (item->name);
2218
2219 gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
2220 w = gtk_menu_item_new_with_label (utf8_label);
2221 gtk_widget_set_sensitive (w, FALSE);
2222 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2223 }
2224 else if (xg_separator_p (item->name))
2225 {
2226 group = NULL;
2227
2228 w = gtk_separator_menu_item_new ();
2229 }
2230 else
2231 {
2232 w = xg_create_one_menuitem (item,
2233 f,
2234 item->contents ? 0 : select_cb,
2235 highlight_cb,
2236 cl_data,
2237 &group);
2238
2239 2240
2241 if (item->contents || menu_bar_p)
2242 {
2243 GtkWidget *submenu = create_menus (item->contents,
2244 f,
2245 select_cb,
2246 deactivate_cb,
2247 highlight_cb,
2248 0,
2249 0,
2250 add_tearoff_p,
2251 0,
2252 cl_data,
2253 0);
2254 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2255 }
2256 }
2257
2258 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
2259 gtk_widget_set_name (w, MENU_ITEM_NAME);
2260 }
2261
2262 return wmenu;
2263 }
2264
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
2279
2280 GtkWidget *
2281 xg_create_widget (type, name, f, val,
2282 select_cb, deactivate_cb, highlight_cb)
2283 char *type;
2284 char *name;
2285 FRAME_PTR f;
2286 widget_value *val;
2287 GCallback select_cb;
2288 GCallback deactivate_cb;
2289 GCallback highlight_cb;
2290 {
2291 GtkWidget *w = 0;
2292 int menu_bar_p = strcmp (type, "menubar") == 0;
2293 int pop_up_p = strcmp (type, "popup") == 0;
2294
2295 if (strcmp (type, "dialog") == 0)
2296 {
2297 w = create_dialog (val, select_cb, deactivate_cb);
2298 xg_set_screen (w, f);
2299 gtk_window_set_transient_for (GTK_WINDOW (w),
2300 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2301 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2302 gtk_widget_set_name (w, "emacs-dialog");
2303 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2304 }
2305 else if (menu_bar_p || pop_up_p)
2306 {
2307 w = create_menus (val->contents,
2308 f,
2309 select_cb,
2310 deactivate_cb,
2311 highlight_cb,
2312 pop_up_p,
2313 menu_bar_p,
2314 menu_bar_p,
2315 0,
2316 0,
2317 name);
2318
2319 2320
2321 if (pop_up_p)
2322 {
2323
2324 gtk_widget_realize (w);
2325 xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
2326 }
2327 }
2328 else
2329 {
2330 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
2331 type);
2332 }
2333
2334 return w;
2335 }
2336
2337
2338
2339 static const char *
2340 xg_get_menu_item_label (witem)
2341 GtkMenuItem *witem;
2342 {
2343 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2344 return gtk_label_get_label (wlabel);
2345 }
2346
2347
2348
2349 static int
2350 xg_item_label_same_p (witem, label)
2351 GtkMenuItem *witem;
2352 char *label;
2353 {
2354 int is_same = 0;
2355 char *utf8_label = get_utf8_string (label);
2356 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
2357
2358 if (! old_label && ! utf8_label)
2359 is_same = 1;
2360 else if (old_label && utf8_label)
2361 is_same = strcmp (utf8_label, old_label) == 0;
2362
2363 if (utf8_label && utf8_label != label) g_free (utf8_label);
2364
2365 return is_same;
2366 }
2367
2368
2369
2370 static void
2371 xg_destroy_widgets (list)
2372 GList *list;
2373 {
2374 GList *iter;
2375
2376 for (iter = list; iter; iter = g_list_next (iter))
2377 {
2378 GtkWidget *w = GTK_WIDGET (iter->data);
2379
2380
2381 gtk_widget_destroy (w);
2382 }
2383 }
2384
2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395
2396
2397 static void
2398 xg_update_menubar (menubar, f, list, iter, pos, val,
2399 select_cb, deactivate_cb, highlight_cb, cl_data)
2400 GtkWidget *menubar;
2401 FRAME_PTR f;
2402 GList **list;
2403 GList *iter;
2404 int pos;
2405 widget_value *val;
2406 GCallback select_cb;
2407 GCallback deactivate_cb;
2408 GCallback highlight_cb;
2409 xg_menu_cb_data *cl_data;
2410 {
2411 if (! iter && ! val)
2412 return;
2413 else if (iter && ! val)
2414 {
2415
2416 xg_destroy_widgets (iter);
2417
2418
2419 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2420 gtk_menu_item_new_with_label (""),
2421 0);
2422
2423 val = 0;
2424 iter = 0;
2425 }
2426 else if (! iter && val)
2427 {
2428
2429 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
2430 0, 1, 0, menubar, cl_data, 0);
2431
2432
2433 val = 0;
2434 iter = 0;
2435 }
2436
2437 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
2438 {
2439
2440 val = val->next;
2441 iter = g_list_next (iter);
2442 ++pos;
2443 }
2444 else
2445 {
2446 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
2447 GtkMenuItem *witem2 = 0;
2448 int val_in_menubar = 0;
2449 int iter_in_new_menubar = 0;
2450 GList *iter2;
2451 widget_value *cur;
2452
2453
2454 for (iter2 = iter;
2455 iter2 && ! val_in_menubar;
2456 iter2 = g_list_next (iter2))
2457 {
2458 witem2 = GTK_MENU_ITEM (iter2->data);
2459 val_in_menubar = xg_item_label_same_p (witem2, val->name);
2460 }
2461
2462 2463
2464 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
2465 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
2466
2467 if (val_in_menubar && ! iter_in_new_menubar)
2468 {
2469 int nr = pos;
2470
2471 2472 2473 2474
2475
2476 gtk_widget_ref (GTK_WIDGET (witem));
2477 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
2478 gtk_widget_destroy (GTK_WIDGET (witem));
2479
2480
2481 g_list_free (*list);
2482 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2483 while (nr-- > 0) iter = g_list_next (iter);
2484 }
2485 else if (! val_in_menubar && ! iter_in_new_menubar)
2486 {
2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500
2501 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2502 char *utf8_label = get_utf8_string (val->name);
2503 GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
2504
2505 gtk_label_set_text (wlabel, utf8_label);
2506
2507 2508
2509 if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
2510
2511 gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
2512
2513 iter = g_list_next (iter);
2514 val = val->next;
2515 ++pos;
2516 }
2517 else if (! val_in_menubar && iter_in_new_menubar)
2518 {
2519 2520 2521 2522
2523
2524 int nr = pos;
2525 GList *group = 0;
2526 GtkWidget *w = xg_create_one_menuitem (val,
2527 f,
2528 select_cb,
2529 highlight_cb,
2530 cl_data,
2531 &group);
2532
2533 2534
2535 GtkWidget *submenu = create_menus (NULL, f,
2536 select_cb, deactivate_cb,
2537 highlight_cb,
2538 0, 0, 0, 0, cl_data, 0);
2539 gtk_widget_set_name (w, MENU_ITEM_NAME);
2540 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
2541 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2542
2543 g_list_free (*list);
2544 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2545 while (nr-- > 0) iter = g_list_next (iter);
2546 iter = g_list_next (iter);
2547 val = val->next;
2548 ++pos;
2549 }
2550 else
2551 {
2552 int nr = pos;
2553 2554 2555 2556
2557
2558 gtk_widget_ref (GTK_WIDGET (witem2));
2559 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
2560 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2561 GTK_WIDGET (witem2), pos);
2562 gtk_widget_unref (GTK_WIDGET (witem2));
2563
2564 g_list_free (*list);
2565 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2566 while (nr-- > 0) iter = g_list_next (iter);
2567 if (iter) iter = g_list_next (iter);
2568 val = val->next;
2569 ++pos;
2570 }
2571 }
2572
2573
2574 xg_update_menubar (menubar, f, list, iter, pos, val,
2575 select_cb, deactivate_cb, highlight_cb, cl_data);
2576 }
2577
2578 2579 2580 2581
2582
2583 static void
2584 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
2585 widget_value *val;
2586 GtkWidget *w;
2587 GCallback select_cb;
2588 GCallback highlight_cb;
2589 xg_menu_cb_data *cl_data;
2590 {
2591 GtkWidget *wchild;
2592 GtkLabel *wlbl = 0;
2593 GtkLabel *wkey = 0;
2594 char *utf8_label;
2595 char *utf8_key;
2596 const char *old_label = 0;
2597 const char *old_key = 0;
2598 xg_menu_item_cb_data *cb_data;
2599
2600 wchild = gtk_bin_get_child (GTK_BIN (w));
2601 utf8_label = get_utf8_string (val->name);
2602 utf8_key = get_utf8_string (val->key);
2603
2604
2605 if (GTK_IS_HBOX (wchild))
2606 {
2607 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
2608
2609 wlbl = GTK_LABEL (list->data);
2610 wkey = GTK_LABEL (list->next->data);
2611 g_list_free (list);
2612
2613 if (! utf8_key)
2614 {
2615
2616 gtk_widget_ref (GTK_WIDGET (wlbl));
2617 gtk_container_remove (GTK_CONTAINER (w), wchild);
2618 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
2619 wkey = 0;
2620 }
2621
2622 }
2623 else
2624 {
2625 wlbl = GTK_LABEL (wchild);
2626
2627
2628 if (utf8_key)
2629 {
2630 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2631 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
2632
2633 wlbl = GTK_LABEL (list->data);
2634 wkey = GTK_LABEL (list->next->data);
2635 g_list_free (list);
2636
2637 gtk_container_remove (GTK_CONTAINER (w), wchild);
2638 gtk_container_add (GTK_CONTAINER (w), wtoadd);
2639 }
2640 }
2641
2642
2643 if (wkey) old_key = gtk_label_get_label (wkey);
2644 if (wlbl) old_label = gtk_label_get_label (wlbl);
2645
2646 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
2647 gtk_label_set_text (wkey, utf8_key);
2648
2649 if (! old_label || strcmp (utf8_label, old_label) != 0)
2650 gtk_label_set_text (wlbl, utf8_label);
2651
2652 if (utf8_key && utf8_key != val->key) g_free (utf8_key);
2653 if (utf8_label && utf8_label != val->name) g_free (utf8_label);
2654
2655 if (! val->enabled && GTK_WIDGET_SENSITIVE (w))
2656 gtk_widget_set_sensitive (w, FALSE);
2657 else if (val->enabled && ! GTK_WIDGET_SENSITIVE (w))
2658 gtk_widget_set_sensitive (w, TRUE);
2659
2660 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
2661 XG_ITEM_DATA);
2662 if (cb_data)
2663 {
2664 cb_data->call_data = val->call_data;
2665 cb_data->help = val->help;
2666 cb_data->cl_data = cl_data;
2667
2668
2669 if (val->call_data && ! val->contents)
2670 {
2671
2672 if (! cb_data->select_id)
2673 cb_data->select_id
2674 = g_signal_connect (G_OBJECT (w), "activate",
2675 select_cb, cb_data);
2676 }
2677 else if (cb_data->select_id)
2678 {
2679 g_signal_handler_disconnect (w, cb_data->select_id);
2680 cb_data->select_id = 0;
2681 }
2682 }
2683 }
2684
2685
2686
2687 static void
2688 xg_update_toggle_item (val, w)
2689 widget_value *val;
2690 GtkWidget *w;
2691 {
2692 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2693 }
2694
2695
2696
2697 static void
2698 xg_update_radio_item (val, w)
2699 widget_value *val;
2700 GtkWidget *w;
2701 {
2702 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2703 }
2704
2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715
2716
2717 static GtkWidget *
2718 xg_update_submenu (submenu, f, val,
2719 select_cb, deactivate_cb, highlight_cb, cl_data)
2720 GtkWidget *submenu;
2721 FRAME_PTR f;
2722 widget_value *val;
2723 GCallback select_cb;
2724 GCallback deactivate_cb;
2725 GCallback highlight_cb;
2726 xg_menu_cb_data *cl_data;
2727 {
2728 GtkWidget *newsub = submenu;
2729 GList *list = 0;
2730 GList *iter;
2731 widget_value *cur;
2732 int has_tearoff_p = 0;
2733 GList *first_radio = 0;
2734
2735 if (submenu)
2736 list = gtk_container_get_children (GTK_CONTAINER (submenu));
2737
2738 for (cur = val, iter = list;
2739 cur && iter;
2740 iter = g_list_next (iter), cur = cur->next)
2741 {
2742 GtkWidget *w = GTK_WIDGET (iter->data);
2743
2744
2745 if (GTK_IS_TEAROFF_MENU_ITEM (w))
2746 {
2747 has_tearoff_p = 1;
2748 iter = g_list_next (iter);
2749 if (iter) w = GTK_WIDGET (iter->data);
2750 else break;
2751 }
2752
2753 2754 2755
2756 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
2757 first_radio = iter;
2758 else if (cur->button_type != BUTTON_TYPE_RADIO
2759 && ! GTK_IS_RADIO_MENU_ITEM (w))
2760 first_radio = 0;
2761
2762 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
2763 {
2764 if (! xg_separator_p (cur->name))
2765 break;
2766 }
2767 else if (GTK_IS_CHECK_MENU_ITEM (w))
2768 {
2769 if (cur->button_type != BUTTON_TYPE_TOGGLE)
2770 break;
2771 xg_update_toggle_item (cur, w);
2772 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2773 }
2774 else if (GTK_IS_RADIO_MENU_ITEM (w))
2775 {
2776 if (cur->button_type != BUTTON_TYPE_RADIO)
2777 break;
2778 xg_update_radio_item (cur, w);
2779 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2780 }
2781 else if (GTK_IS_MENU_ITEM (w))
2782 {
2783 GtkMenuItem *witem = GTK_MENU_ITEM (w);
2784 GtkWidget *sub;
2785
2786 if (cur->button_type != BUTTON_TYPE_NONE ||
2787 xg_separator_p (cur->name))
2788 break;
2789
2790 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2791
2792 sub = gtk_menu_item_get_submenu (witem);
2793 if (sub && ! cur->contents)
2794 {
2795
2796 gtk_widget_ref (sub);
2797 gtk_menu_item_remove_submenu (witem);
2798 gtk_widget_destroy (sub);
2799 }
2800 else if (cur->contents)
2801 {
2802 GtkWidget *nsub;
2803
2804 nsub = xg_update_submenu (sub, f, cur->contents,
2805 select_cb, deactivate_cb,
2806 highlight_cb, cl_data);
2807
2808
2809 if (nsub != sub)
2810 gtk_menu_item_set_submenu (witem, nsub);
2811 }
2812 }
2813 else
2814 {
2815 2816
2817 break;
2818 }
2819 }
2820
2821
2822 if (iter)
2823 {
2824 2825
2826 if (cur && first_radio) xg_destroy_widgets (first_radio);
2827 else xg_destroy_widgets (iter);
2828 }
2829
2830 if (cur)
2831 {
2832
2833 newsub = create_menus (cur,
2834 f,
2835 select_cb,
2836 deactivate_cb,
2837 highlight_cb,
2838 0,
2839 0,
2840 ! has_tearoff_p,
2841 submenu,
2842 cl_data,
2843 0);
2844 }
2845
2846 if (list) g_list_free (list);
2847
2848 return newsub;
2849 }
2850
2851 2852 2853 2854 2855 2856 2857 2858
2859
2860 void
2861 xg_modify_menubar_widgets (menubar, f, val, deep_p,
2862 select_cb, deactivate_cb, highlight_cb)
2863 GtkWidget *menubar;
2864 FRAME_PTR f;
2865 widget_value *val;
2866 int deep_p;
2867 GCallback select_cb;
2868 GCallback deactivate_cb;
2869 GCallback highlight_cb;
2870 {
2871 xg_menu_cb_data *cl_data;
2872 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
2873
2874 if (! list) return;
2875
2876 cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
2877 XG_FRAME_DATA);
2878
2879 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
2880 select_cb, deactivate_cb, highlight_cb, cl_data);
2881
2882 if (deep_p)
2883 {
2884 widget_value *cur;
2885
2886 2887 2888
2889
2890
2891 update_cl_data (cl_data, f, highlight_cb);
2892
2893 for (cur = val->contents; cur; cur = cur->next)
2894 {
2895 GList *iter;
2896 GtkWidget *sub = 0;
2897 GtkWidget *newsub;
2898 GtkMenuItem *witem;
2899
2900
2901 for (iter = list ; iter; iter = g_list_next (iter))
2902 {
2903 witem = GTK_MENU_ITEM (iter->data);
2904 if (xg_item_label_same_p (witem, cur->name))
2905 {
2906 sub = gtk_menu_item_get_submenu (witem);
2907 break;
2908 }
2909 }
2910
2911 newsub = xg_update_submenu (sub,
2912 f,
2913 cur->contents,
2914 select_cb,
2915 deactivate_cb,
2916 highlight_cb,
2917 cl_data);
2918 2919 2920
2921 if (newsub != sub)
2922 {
2923 xg_set_screen (newsub, f);
2924 gtk_menu_item_set_submenu (witem, newsub);
2925 }
2926 }
2927 }
2928
2929 g_list_free (list);
2930 gtk_widget_show_all (menubar);
2931 }
2932
2933 2934
2935
2936 int
2937 xg_update_frame_menubar (f)
2938 FRAME_PTR f;
2939 {
2940 struct x_output *x = f->output_data.x;
2941 GtkRequisition req;
2942
2943 if (!x->menubar_widget || GTK_WIDGET_MAPPED (x->menubar_widget))
2944 return 0;
2945
2946 if (x->menubar_widget && gtk_widget_get_parent (x->menubar_widget))
2947 return 0;
2948
2949 BLOCK_INPUT;
2950
2951 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
2952 FALSE, FALSE, 0);
2953 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
2954
2955 gtk_widget_show_all (x->menubar_widget);
2956 gtk_widget_size_request (x->menubar_widget, &req);
2957 FRAME_MENUBAR_HEIGHT (f) = req.height;
2958 xg_height_changed (f);
2959 UNBLOCK_INPUT;
2960
2961 return 1;
2962 }
2963
2964 2965
2966
2967 void
2968 free_frame_menubar (f)
2969 FRAME_PTR f;
2970 {
2971 struct x_output *x = f->output_data.x;
2972
2973 if (x->menubar_widget)
2974 {
2975 BLOCK_INPUT;
2976
2977 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
2978 2979
2980 x->menubar_widget = 0;
2981 FRAME_MENUBAR_HEIGHT (f) = 0;
2982 xg_height_changed (f);
2983 UNBLOCK_INPUT;
2984 }
2985 }
2986
2987
2988
2989 2990 2991
2992
2993
2994 2995
2996
2997 int xg_ignore_gtk_scrollbar;
2998
2999 3000 3001
3002
3003 static struct
3004 {
3005 GtkWidget **widgets;
3006 int max_size;
3007 int used;
3008 } id_to_widget;
3009
3010
3011
3012 #define ID_TO_WIDGET_INCR 32
3013
3014
3015
3016 static int
3017 xg_store_widget_in_map (w)
3018 GtkWidget *w;
3019 {
3020 int i;
3021
3022 if (id_to_widget.max_size == id_to_widget.used)
3023 {
3024 int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
3025
3026 id_to_widget.widgets = xrealloc (id_to_widget.widgets,
3027 sizeof (GtkWidget *)*new_size);
3028
3029 for (i = id_to_widget.max_size; i < new_size; ++i)
3030 id_to_widget.widgets[i] = 0;
3031 id_to_widget.max_size = new_size;
3032 }
3033
3034 3035 3036
3037 for (i = 0; i < id_to_widget.max_size; ++i)
3038 {
3039 if (! id_to_widget.widgets[i])
3040 {
3041 id_to_widget.widgets[i] = w;
3042 ++id_to_widget.used;
3043
3044 return i;
3045 }
3046 }
3047
3048
3049 abort ();
3050 }
3051
3052 3053
3054
3055 static void
3056 xg_remove_widget_from_map (idx)
3057 int idx;
3058 {
3059 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3060 {
3061 id_to_widget.widgets[idx] = 0;
3062 --id_to_widget.used;
3063 }
3064 }
3065
3066
3067
3068 static GtkWidget *
3069 xg_get_widget_from_map (idx)
3070 int idx;
3071 {
3072 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3073 return id_to_widget.widgets[idx];
3074
3075 return 0;
3076 }
3077
3078 3079
3080
3081 int
3082 xg_get_scroll_id_for_window (dpy, wid)
3083 Display *dpy;
3084 Window wid;
3085 {
3086 int idx;
3087 GtkWidget *w;
3088
3089 w = xg_win_to_widget (dpy, wid);
3090
3091 if (w)
3092 {
3093 for (idx = 0; idx < id_to_widget.max_size; ++idx)
3094 if (id_to_widget.widgets[idx] == w)
3095 return idx;
3096 }
3097
3098 return -1;
3099 }
3100
3101 3102 3103
3104
3105 static void
3106 xg_gtk_scroll_destroy (widget, data)
3107 GtkWidget *widget;
3108 gpointer data;
3109 {
3110 int id = (int) (EMACS_INT) data;
3111 xg_remove_widget_from_map (id);
3112 }
3113
3114 3115 3116 3117 3118 3119 3120
3121
3122 void
3123 xg_create_scroll_bar (f, bar, scroll_callback, end_callback, scroll_bar_name)
3124 FRAME_PTR f;
3125 struct scroll_bar *bar;
3126 GCallback scroll_callback, end_callback;
3127 char *scroll_bar_name;
3128 {
3129 GtkWidget *wscroll;
3130 GtkWidget *webox;
3131 GtkObject *vadj;
3132 int scroll_id;
3133
3134 3135
3136 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
3137 0.1, 0.1, 0.1);
3138
3139 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3140 webox = gtk_event_box_new ();
3141 gtk_widget_set_name (wscroll, scroll_bar_name);
3142 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
3143 g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f);
3144
3145 scroll_id = xg_store_widget_in_map (wscroll);
3146
3147
3148 g_signal_connect (G_OBJECT (wscroll),
3149 "destroy",
3150 G_CALLBACK (xg_gtk_scroll_destroy),
3151 (gpointer) (EMACS_INT) scroll_id);
3152 g_signal_connect (G_OBJECT (wscroll),
3153 "change-value",
3154 scroll_callback,
3155 (gpointer) bar);
3156 g_signal_connect (G_OBJECT (wscroll),
3157 "button-release-event",
3158 end_callback,
3159 (gpointer) bar);
3160
3161 3162 3163 3164 3165 3166
3167 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
3168 gtk_container_add (GTK_CONTAINER (webox), wscroll);
3169
3170
3171
3172 xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
3173
3174 bar->x_window = scroll_id;
3175 }
3176
3177
3178
3179 void
3180 xg_show_scroll_bar (scrollbar_id)
3181 int scrollbar_id;
3182 {
3183 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3184 if (w)
3185 gtk_widget_show_all (gtk_widget_get_parent (w));
3186 }
3187
3188
3189
3190 void
3191 xg_remove_scroll_bar (f, scrollbar_id)
3192 FRAME_PTR f;
3193 int scrollbar_id;
3194 {
3195 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3196 if (w)
3197 {
3198 GtkWidget *wparent = gtk_widget_get_parent (w);
3199 gtk_widget_destroy (w);
3200 gtk_widget_destroy (wparent);
3201 SET_FRAME_GARBAGED (f);
3202 }
3203 }
3204
3205 3206 3207 3208
3209
3210 void
3211 xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
3212 FRAME_PTR f;
3213 int scrollbar_id;
3214 int top;
3215 int left;
3216 int width;
3217 int height;
3218 {
3219
3220 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
3221
3222 if (wscroll)
3223 {
3224 GtkWidget *wfixed = f->output_data.x->edit_widget;
3225 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
3226 GtkFixed *wf = GTK_FIXED (wfixed);
3227
3228
3229 GList *iter;
3230 int oldx = -1, oldy = -1, oldw, oldh;
3231 for (iter = wf->children; iter; iter = iter->next)
3232 if (((GtkFixedChild *)iter->data)->widget == wparent)
3233 {
3234 GtkFixedChild *ch = (GtkFixedChild *)iter->data;
3235 if (ch->x != left || ch->y != top)
3236 {
3237 oldx = ch->x;
3238 oldy = ch->y;
3239 gtk_widget_get_size_request (wscroll, &oldw, &oldh);
3240 }
3241 break;
3242 }
3243
3244
3245 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
3246 gtk_widget_set_size_request (wscroll, width, height);
3247 gtk_widget_queue_draw (wfixed);
3248 gdk_window_process_all_updates ();
3249 if (oldx != -1)
3250 {
3251 3252 3253
3254 x_clear_area (FRAME_X_DISPLAY (f),
3255 FRAME_X_WINDOW (f),
3256 oldx, oldy, oldw, oldh, 0);
3257 }
3258
3259 3260 3261
3262
3263 x_sync (f);
3264 SET_FRAME_GARBAGED (f);
3265 cancel_mouse_face (f);
3266 }
3267 }
3268
3269 3270
3271
3272 void
3273 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
3274 struct scroll_bar *bar;
3275 int portion, position, whole;
3276 {
3277 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
3278
3279 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3280
3281 if (wscroll && NILP (bar->dragging))
3282 {
3283 GtkAdjustment *adj;
3284 gdouble shown;
3285 gdouble top;
3286 int size, value;
3287 int new_step;
3288 int changed = 0;
3289
3290 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
3291
3292 3293 3294
3295 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
3296 3297
3298 whole += portion;
3299
3300 if (whole <= 0)
3301 top = 0, shown = 1;
3302 else
3303 {
3304 top = (gdouble) position / whole;
3305 shown = (gdouble) portion / whole;
3306 }
3307
3308 size = shown * XG_SB_RANGE;
3309 size = min (size, XG_SB_RANGE);
3310 size = max (size, 1);
3311
3312 value = top * XG_SB_RANGE;
3313 value = min (value, XG_SB_MAX - size);
3314 value = max (value, XG_SB_MIN);
3315
3316
3317 new_step = size / max (1, FRAME_LINES (f));
3318
3319 if ((int) adj->page_size != size
3320 || (int) adj->step_increment != new_step)
3321 {
3322 adj->page_size = size;
3323 adj->step_increment = new_step;
3324
3325 adj->page_increment = (int) (0.95*adj->page_size);
3326 changed = 1;
3327 }
3328
3329 if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3330 {
3331 BLOCK_INPUT;
3332
3333 3334
3335 xg_ignore_gtk_scrollbar = 1;
3336
3337 if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3338 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
3339 else if (changed)
3340 gtk_adjustment_changed (adj);
3341
3342 xg_ignore_gtk_scrollbar = 0;
3343
3344 UNBLOCK_INPUT;
3345 }
3346 }
3347 }
3348
3349 3350 3351 3352 3353 3354
3355
3356 int
3357 xg_event_is_for_scrollbar (f, event)
3358 FRAME_PTR f;
3359 XEvent *event;
3360 {
3361 int retval = 0;
3362
3363 if (f && event->type == ButtonPress && event->xbutton.button < 4)
3364 {
3365
3366 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
3367 retval = gdk_display_get_window_at_pointer (gdpy, NULL, NULL)
3368 != f->output_data.x->edit_widget->window;
3369 }
3370 else if (f
3371 && ((event->type == ButtonRelease && event->xbutton.button < 4)
3372 || event->type == MotionNotify))
3373 {
3374
3375 GtkWidget *w = gtk_grab_get_current ();
3376 retval = w != 0 && GTK_IS_SCROLLBAR (w);
3377 }
3378
3379 return retval;
3380 }
3381
3382
3383
3384 3385 3386
3387 3388 3389
3390 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
3391
3392 3393
3394 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
3395
3396
3397 #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
3398
3399 3400 3401
3402 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
3403
3404 3405
3406 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
3407
3408 3409 3410 3411
3412
3413 static gboolean
3414 xg_tool_bar_button_cb (widget, event, user_data)
3415 GtkWidget *widget;
3416 GdkEventButton *event;
3417 gpointer user_data;
3418 {
3419
3420 gpointer ptr = (gpointer) (EMACS_INT) event->state;
3421 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
3422 return FALSE;
3423 }
3424
3425
3426 3427 3428 3429
3430
3431 static void
3432 xg_tool_bar_callback (w, client_data)
3433 GtkWidget *w;
3434 gpointer client_data;
3435 {
3436
3437 int idx = (int) (EMACS_INT) client_data;
3438 int mod = (int) (EMACS_INT) g_object_get_data (G_OBJECT (w),
3439 XG_TOOL_BAR_LAST_MODIFIER);
3440
3441 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3442 Lisp_Object key, frame;
3443 struct input_event event;
3444 EVENT_INIT (event);
3445
3446 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3447 return;
3448
3449 idx *= TOOL_BAR_ITEM_NSLOTS;
3450
3451 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
3452 XSETFRAME (frame, f);
3453
3454 3455
3456 event.kind = TOOL_BAR_EVENT;
3457 event.frame_or_window = frame;
3458 event.arg = frame;
3459 kbd_buffer_store_event (&event);
3460
3461 event.kind = TOOL_BAR_EVENT;
3462 event.frame_or_window = frame;
3463 event.arg = key;
3464 3465 3466
3467 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
3468 kbd_buffer_store_event (&event);
3469
3470 3471
3472 Fx_focus_frame (frame);
3473 }
3474
3475 3476 3477 3478 3479 3480
3481
3482 static void
3483 xg_tool_bar_proxy_callback (w, client_data)
3484 GtkWidget *w;
3485 gpointer client_data;
3486 {
3487 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3488 XG_TOOL_BAR_PROXY_BUTTON));
3489 xg_tool_bar_callback (wbutton, client_data);
3490 }
3491
3492
3493 static gboolean
3494 xg_tool_bar_help_callback P_ ((GtkWidget *w,
3495 GdkEventCrossing *event,
3496 gpointer client_data));
3497
3498 3499
3500
3501 static gboolean
3502 xg_tool_bar_proxy_help_callback (w, event, client_data)
3503 GtkWidget *w;
3504 GdkEventCrossing *event;
3505 gpointer client_data;
3506 {
3507 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3508 XG_TOOL_BAR_PROXY_BUTTON));
3509
3510 return xg_tool_bar_help_callback (wbutton, event, client_data);
3511 }
3512
3513
3514 3515 3516 3517
3518
3519 static gboolean
3520 xg_tool_bar_menu_proxy (toolitem, user_data)
3521 GtkToolItem *toolitem;
3522 gpointer user_data;
3523 {
3524 GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
3525 GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
3526 GtkBox *vb = GTK_BOX (gtk_bin_get_child (GTK_BIN (wbutton)));
3527 GtkBoxChild *c1 = (GtkBoxChild *) vb->children->data;
3528 GtkBoxChild *c2 = (GtkBoxChild *) vb->children->next->data;
3529 GtkImage *wimage = GTK_IS_IMAGE (c1->widget)
3530 ? GTK_IMAGE (c1->widget) : GTK_IMAGE (c2->widget);
3531 GtkLabel *wlbl = GTK_IS_LABEL (c1->widget)
3532 ? GTK_LABEL (c1->widget) : GTK_LABEL (c2->widget);
3533 GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label
3534 (gtk_label_get_text (wlbl));
3535
3536 GtkWidget *wmenuimage;
3537
3538 if (gtk_button_get_use_stock (wbutton))
3539 wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
3540 GTK_ICON_SIZE_MENU);
3541 else
3542 {
3543 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
3544 GtkImageType store_type = gtk_image_get_storage_type (wimage);
3545
3546 if (store_type == GTK_IMAGE_STOCK)
3547 {
3548 gchar *stock_id;
3549 gtk_image_get_stock (wimage, &stock_id, NULL);
3550 wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
3551 }
3552 else if (store_type == GTK_IMAGE_ICON_SET)
3553 {
3554 GtkIconSet *icon_set;
3555 gtk_image_get_icon_set (wimage, &icon_set, NULL);
3556 wmenuimage = gtk_image_new_from_icon_set (icon_set,
3557 GTK_ICON_SIZE_MENU);
3558 }
3559 else if (store_type == GTK_IMAGE_PIXBUF)
3560 {
3561 gint width, height;
3562
3563 if (settings &&
3564 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
3565 &width, &height))
3566 {
3567 GdkPixbuf *src_pixbuf, *dest_pixbuf;
3568
3569 src_pixbuf = gtk_image_get_pixbuf (wimage);
3570 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
3571 GDK_INTERP_BILINEAR);
3572
3573 wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
3574 }
3575 else
3576 {
3577 fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
3578 abort ();
3579 }
3580 }
3581 else if (store_type == GTK_IMAGE_ICON_NAME)
3582 {
3583 const gchar *icon_name;
3584 GtkIconSize icon_size;
3585
3586 gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
3587 wmenuimage = gtk_image_new_from_icon_name (icon_name,
3588 GTK_ICON_SIZE_MENU);
3589 }
3590 else
3591 {
3592 fprintf (stderr, "internal error: store_type is %d\n", store_type);
3593 abort ();
3594 }
3595 }
3596 if (wmenuimage)
3597 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
3598
3599 g_signal_connect (G_OBJECT (wmenuitem),
3600 "activate",
3601 G_CALLBACK (xg_tool_bar_proxy_callback),
3602 user_data);
3603
3604
3605 g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
3606 (gpointer) wbutton);
3607 gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
3608 gtk_widget_set_sensitive (wmenuitem, GTK_WIDGET_SENSITIVE (wbutton));
3609
3610 3611 3612 3613
3614 g_signal_connect (G_OBJECT (wmenuitem),
3615 "enter-notify-event",
3616 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3617 user_data);
3618 g_signal_connect (G_OBJECT (wmenuitem),
3619 "leave-notify-event",
3620 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3621 user_data);
3622
3623 return TRUE;
3624 }
3625
3626 3627 3628 3629 3630 3631
3632
3633 static void
3634 xg_tool_bar_detach_callback (wbox, w, client_data)
3635 GtkHandleBox *wbox;
3636 GtkWidget *w;
3637 gpointer client_data;
3638 {
3639 FRAME_PTR f = (FRAME_PTR) client_data;
3640 extern int x_gtk_whole_detached_tool_bar;
3641
3642 g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
3643 NULL);
3644
3645 if (f)
3646 {
3647 FRAME_X_OUTPUT (f)->toolbar_detached = 1;
3648
3649 3650 3651
3652 FRAME_TOOLBAR_HEIGHT (f) = 4;
3653 xg_height_changed (f);
3654 }
3655 }
3656
3657 3658 3659 3660 3661 3662
3663
3664 static void
3665 xg_tool_bar_attach_callback (wbox, w, client_data)
3666 GtkHandleBox *wbox;
3667 GtkWidget *w;
3668 gpointer client_data;
3669 {
3670 FRAME_PTR f = (FRAME_PTR) client_data;
3671 g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
3672
3673 if (f)
3674 {
3675 GtkRequisition req;
3676
3677 FRAME_X_OUTPUT (f)->toolbar_detached = 0;
3678
3679 gtk_widget_size_request (w, &req);
3680 FRAME_TOOLBAR_HEIGHT (f) = req.height;
3681 xg_height_changed (f);
3682 }
3683 }
3684
3685 3686 3687 3688 3689 3690 3691 3692
3693
3694 static gboolean
3695 xg_tool_bar_help_callback (w, event, client_data)
3696 GtkWidget *w;
3697 GdkEventCrossing *event;
3698 gpointer client_data;
3699 {
3700
3701 int idx = (int) (EMACS_INT) client_data;
3702 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3703 Lisp_Object help, frame;
3704
3705 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3706 return FALSE;
3707
3708 if (event->type == GDK_ENTER_NOTIFY)
3709 {
3710 idx *= TOOL_BAR_ITEM_NSLOTS;
3711 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
3712
3713 if (NILP (help))
3714 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
3715 }
3716 else
3717 help = Qnil;
3718
3719 XSETFRAME (frame, f);
3720 kbd_buffer_store_help_event (frame, help);
3721
3722 return FALSE;
3723 }
3724
3725
3726 3727 3728 3729 3730 3731 3732 3733 3734
3735
3736 static gboolean
3737 xg_tool_bar_item_expose_callback (w, event, client_data)
3738 GtkWidget *w;
3739 GdkEventExpose *event;
3740 gpointer client_data;
3741 {
3742 gint width, height;
3743
3744 gdk_drawable_get_size (event->window, &width, &height);
3745
3746 event->area.x -= width > event->area.width ? width-event->area.width : 0;
3747 event->area.y -= height > event->area.height ? height-event->area.height : 0;
3748
3749 event->area.x = max (0, event->area.x);
3750 event->area.y = max (0, event->area.y);
3751
3752 event->area.width = max (width, event->area.width);
3753 event->area.height = max (height, event->area.height);
3754
3755 return FALSE;
3756 }
3757
3758
3759
3760 static void
3761 xg_pack_tool_bar (f)
3762 FRAME_PTR f;
3763 {
3764 struct x_output *x = f->output_data.x;
3765 int vbox_pos = x->menubar_widget ? 1 : 0;
3766
3767 x->handlebox_widget = gtk_handle_box_new ();
3768 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
3769 G_CALLBACK (xg_tool_bar_detach_callback), f);
3770 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
3771 G_CALLBACK (xg_tool_bar_attach_callback), f);
3772
3773 gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
3774 x->toolbar_widget);
3775
3776 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3777 FALSE, FALSE, 0);
3778
3779 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3780 vbox_pos);
3781
3782 gtk_widget_show (x->toolbar_widget);
3783 gtk_widget_show (x->handlebox_widget);
3784 }
3785
3786
3787
3788 static void
3789 xg_create_tool_bar (f)
3790 FRAME_PTR f;
3791 {
3792 struct x_output *x = f->output_data.x;
3793
3794 x->toolbar_widget = gtk_toolbar_new ();
3795 x->toolbar_detached = 0;
3796
3797 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
3798
3799 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
3800 gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
3801 GTK_ORIENTATION_HORIZONTAL);
3802 }
3803
3804
3805 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
3806
3807 3808
3809
3810 static Lisp_Object
3811 find_rtl_image (f, image, rtl)
3812 FRAME_PTR f;
3813 Lisp_Object image;
3814 Lisp_Object rtl;
3815 {
3816 int i;
3817 Lisp_Object file, rtl_name;
3818 struct gcpro gcpro1, gcpro2;
3819 GCPRO2 (file, rtl_name);
3820
3821 rtl_name = Ffile_name_nondirectory (rtl);
3822
3823 for (i = 0; i < f->n_tool_bar_items; ++i)
3824 {
3825 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
3826 if (!NILP (file = file_for_image (rtl_image)))
3827 {
3828 file = call1 (intern ("file-name-sans-extension"),
3829 Ffile_name_nondirectory (file));
3830 if (EQ (Fequal (file, rtl_name), Qt))
3831 {
3832 image = rtl_image;
3833 break;
3834 }
3835 }
3836 }
3837
3838 return image;
3839 }
3840
3841 static GtkToolItem *
3842 xg_make_tool_item (FRAME_PTR f,
3843 GtkWidget *wimage,
3844 GtkWidget **wbutton,
3845 char *label,
3846 int i)
3847 {
3848 GtkToolItem *ti = gtk_tool_item_new ();
3849 GtkWidget *vb = EQ (Vtool_bar_style, Qboth_horiz)
3850 ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0);
3851 GtkWidget *wb = gtk_button_new ();
3852 GtkWidget *weventbox = gtk_event_box_new ();
3853
3854 if (wimage)
3855 gtk_box_pack_start_defaults (GTK_BOX (vb), wimage);
3856
3857 gtk_box_pack_start_defaults (GTK_BOX (vb), gtk_label_new (label));
3858 gtk_button_set_focus_on_click (GTK_BUTTON (wb), FALSE);
3859 gtk_button_set_relief (GTK_BUTTON (wb), GTK_RELIEF_NONE);
3860 gtk_container_add (GTK_CONTAINER (wb), vb);
3861 gtk_container_add (GTK_CONTAINER (weventbox), wb);
3862 gtk_container_add (GTK_CONTAINER (ti), weventbox);
3863
3864 if (wimage)
3865 {
3866
3867 g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
3868 G_CALLBACK (xg_tool_bar_menu_proxy),
3869 (gpointer) (EMACS_INT) i);
3870
3871 g_signal_connect (G_OBJECT (wb), "clicked",
3872 G_CALLBACK (xg_tool_bar_callback),
3873 (gpointer) (EMACS_INT) i);
3874
3875 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
3876
3877 3878
3879 g_signal_connect (G_OBJECT (ti),
3880 "expose-event",
3881 G_CALLBACK (xg_tool_bar_item_expose_callback),
3882 0);
3883
3884 gtk_tool_item_set_homogeneous (ti, FALSE);
3885
3886 3887 3888
3889 g_signal_connect (wb, "button-release-event",
3890 G_CALLBACK (xg_tool_bar_button_cb),
3891 NULL);
3892
3893 g_object_set_data (G_OBJECT (wb), XG_FRAME_DATA, (gpointer)f);
3894
3895 3896 3897 3898
3899
3900 g_signal_connect (G_OBJECT (weventbox),
3901 "enter-notify-event",
3902 G_CALLBACK (xg_tool_bar_help_callback),
3903 (gpointer) (EMACS_INT) i);
3904 g_signal_connect (G_OBJECT (weventbox),
3905 "leave-notify-event",
3906 G_CALLBACK (xg_tool_bar_help_callback),
3907 (gpointer) (EMACS_INT) i);
3908 }
3909
3910 if (wbutton) *wbutton = wb;
3911
3912 return ti;
3913 }
3914
3915 static void
3916 xg_show_toolbar_item (GtkToolItem *ti)
3917 {
3918 Lisp_Object style = Ftool_bar_get_system_style ();
3919
3920 int show_label = EQ (style, Qboth)
3921 || EQ (style, Qboth_horiz) || EQ (style, Qtext);
3922 int show_image = ! EQ (style, Qtext);
3923 int horiz = EQ (style, Qboth_horiz);
3924
3925 GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (ti));
3926 GtkWidget *wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
3927 GtkBox *vb = GTK_BOX (gtk_bin_get_child (GTK_BIN (wbutton)));
3928 GtkBoxChild *c1 = (GtkBoxChild *) vb->children->data;
3929 GtkBoxChild *c2 = (GtkBoxChild *) vb->children->next->data;
3930 GtkWidget *wimage = GTK_IS_IMAGE (c1->widget)
3931 ? c1->widget : c2->widget;
3932 GtkWidget *wlbl = GTK_IS_LABEL (c1->widget)
3933 ? c1->widget : c2->widget;
3934 GtkWidget *new_box = NULL;
3935
3936 if (GTK_IS_VBOX (vb) && horiz)
3937 new_box = gtk_hbox_new (FALSE, 0);
3938 else if (GTK_IS_HBOX (vb) && !horiz && show_label && show_image)
3939 new_box = gtk_vbox_new (FALSE, 0);
3940 if (new_box)
3941 {
3942 gtk_widget_ref (wimage);
3943 gtk_widget_ref (wlbl);
3944 gtk_container_remove (GTK_CONTAINER (vb), wimage);
3945 gtk_container_remove (GTK_CONTAINER (vb), wlbl);
3946 gtk_widget_destroy (GTK_WIDGET (vb));
3947 gtk_box_pack_start_defaults (GTK_BOX (new_box), wimage);
3948 gtk_box_pack_start_defaults (GTK_BOX (new_box), wlbl);
3949 gtk_container_add (GTK_CONTAINER (wbutton), new_box);
3950 gtk_widget_unref (wimage);
3951 gtk_widget_unref (wlbl);
3952 vb = GTK_BOX (new_box);
3953 }
3954
3955 if (show_label) gtk_widget_show (wlbl);
3956 else gtk_widget_hide (wlbl);
3957 if (show_image) gtk_widget_show (wimage);
3958 else gtk_widget_hide (wimage);
3959 gtk_widget_show (GTK_WIDGET (weventbox));
3960 gtk_widget_show (GTK_WIDGET (vb));
3961 gtk_widget_show (GTK_WIDGET (wbutton));
3962 gtk_widget_show (GTK_WIDGET (ti));
3963 }
3964
3965
3966
3967
3968 extern Lisp_Object Qx_gtk_map_stock;
3969
3970 void
3971 update_frame_tool_bar (f)
3972 FRAME_PTR f;
3973 {
3974 int i;
3975 GtkRequisition old_req, new_req;
3976 struct x_output *x = f->output_data.x;
3977 int hmargin = 0, vmargin = 0;
3978 GtkToolbar *wtoolbar;
3979 GtkToolItem *ti;
3980 GtkTextDirection dir;
3981 int pack_tool_bar = x->handlebox_widget == NULL;
3982
3983 if (! FRAME_GTK_WIDGET (f))
3984 return;
3985
3986 BLOCK_INPUT;
3987
3988 if (INTEGERP (Vtool_bar_button_margin)
3989 && XINT (Vtool_bar_button_margin) > 0)
3990 {
3991 hmargin = XFASTINT (Vtool_bar_button_margin);
3992 vmargin = XFASTINT (Vtool_bar_button_margin);
3993 }
3994 else if (CONSP (Vtool_bar_button_margin))
3995 {
3996 if (INTEGERP (XCAR (Vtool_bar_button_margin))
3997 && XINT (XCAR (Vtool_bar_button_margin)) > 0)
3998 hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
3999
4000 if (INTEGERP (XCDR (Vtool_bar_button_margin))
4001 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4002 vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
4003 }
4004
4005 4006 4007 4008
4009 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
4010 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
4011
4012 if (! x->toolbar_widget)
4013 xg_create_tool_bar (f);
4014
4015 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
4016 gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
4017 dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar));
4018
4019 for (i = 0; i < f->n_tool_bar_items; ++i)
4020 {
4021 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
4022 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
4023 int idx;
4024 int img_id;
4025 int icon_size = 0;
4026 struct image *img = NULL;
4027 Lisp_Object image;
4028 Lisp_Object stock = Qnil;
4029 GtkStockItem stock_item;
4030 char *stock_name = NULL;
4031 char *icon_name = NULL;
4032 Lisp_Object rtl;
4033 GtkWidget *wbutton = NULL;
4034 GtkWidget *weventbox;
4035 Lisp_Object specified_file;
4036 Lisp_Object lbl = PROP (TOOL_BAR_ITEM_LABEL);
4037 char *label = SSDATA (PROP (TOOL_BAR_ITEM_LABEL));
4038
4039 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i);
4040
4041 if (ti)
4042 {
4043 weventbox = gtk_bin_get_child (GTK_BIN (ti));
4044 wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
4045 }
4046
4047
4048 image = PROP (TOOL_BAR_ITEM_IMAGES);
4049
4050
4051 if (!valid_image_p (image))
4052 {
4053 if (wbutton) gtk_widget_hide (wbutton);
4054 continue;
4055 }
4056
4057 specified_file = file_for_image (image);
4058 if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
4059 stock = call1 (Qx_gtk_map_stock, specified_file);
4060
4061 if (STRINGP (stock))
4062 {
4063 stock_name = SSDATA (stock);
4064 if (stock_name[0] == 'n' && stock_name[1] == ':')
4065 {
4066 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
4067 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
4068
4069 icon_name = stock_name + 2;
4070 stock_name = NULL;
4071 stock = Qnil;
4072
4073 if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
4074 icon_name = NULL;
4075 else
4076 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4077 }
4078 else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
4079 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4080 else
4081 {
4082 stock = Qnil;
4083 stock_name = NULL;
4084 }
4085 }
4086
4087 if (stock_name == NULL && icon_name == NULL)
4088 {
4089
4090
4091 4092
4093 if (dir == GTK_TEXT_DIR_RTL
4094 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
4095 && STRINGP (rtl))
4096 {
4097 image = find_rtl_image (f, image, rtl);
4098 }
4099
4100 if (VECTORP (image))
4101 {
4102 if (enabled_p)
4103 idx = (selected_p
4104 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
4105 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
4106 else
4107 idx = (selected_p
4108 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
4109 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
4110
4111 xassert (ASIZE (image) >= idx);
4112 image = AREF (image, idx);
4113 }
4114 else
4115 idx = -1;
4116
4117 img_id = lookup_image (f, image);
4118 img = IMAGE_FROM_ID (f, img_id);
4119 prepare_image_for_display (f, img);
4120
4121 if (img->load_failed_p || img->pixmap == None)
4122 {
4123 if (ti)
4124 gtk_widget_hide_all (GTK_WIDGET (ti));
4125 else
4126 {
4127
4128 ti = xg_make_tool_item (f, NULL, NULL, "", i);
4129 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
4130 }
4131 continue;
4132 }
4133 }
4134
4135 if (ti == NULL)
4136 {
4137 GtkWidget *w;
4138 if (stock_name)
4139 {
4140 w = gtk_image_new_from_stock (stock_name, icon_size);
4141 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
4142 (gpointer) xstrdup (stock_name),
4143 (GDestroyNotify) xfree);
4144 }
4145 else if (icon_name)
4146 {
4147 w = gtk_image_new_from_icon_name (icon_name, icon_size);
4148 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
4149 (gpointer) xstrdup (icon_name),
4150 (GDestroyNotify) xfree);
4151 }
4152 else
4153 {
4154 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
4155 4156
4157 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
4158 (gpointer)img->pixmap);
4159 }
4160
4161 gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
4162 ti = xg_make_tool_item (f, w, &wbutton, label, i);
4163 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
4164 gtk_widget_set_sensitive (wbutton, enabled_p);
4165 }
4166 else
4167 {
4168 GtkBox *vb = GTK_BOX (gtk_bin_get_child (GTK_BIN (wbutton)));
4169 GtkBoxChild *c1 = (GtkBoxChild *) vb->children->data;
4170 GtkBoxChild *c2 = (GtkBoxChild *) vb->children->next->data;
4171 GtkWidget *wimage = GTK_IS_IMAGE (c1->widget)
4172 ? c1->widget : c2->widget;
4173 GtkWidget *wlbl = GTK_IS_LABEL (c1->widget)
4174 ? c1->widget : c2->widget;
4175
4176 Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
4177 XG_TOOL_BAR_IMAGE_DATA);
4178 gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
4179 XG_TOOL_BAR_STOCK_NAME);
4180 gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
4181 XG_TOOL_BAR_ICON_NAME);
4182 gtk_label_set_text (GTK_LABEL (wlbl), label);
4183 if (stock_name &&
4184 (! old_stock_name || strcmp (old_stock_name, stock_name) != 0))
4185 {
4186 gtk_image_set_from_stock (GTK_IMAGE (wimage),
4187 stock_name, icon_size);
4188 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4189 (gpointer) xstrdup (stock_name),
4190 (GDestroyNotify) xfree);
4191 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4192 NULL);
4193 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4194 NULL);
4195 }
4196 else if (icon_name &&
4197 (! old_icon_name || strcmp (old_icon_name, icon_name) != 0))
4198 {
4199 gtk_image_set_from_icon_name (GTK_IMAGE (wimage),
4200 icon_name, icon_size);
4201 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4202 (gpointer) xstrdup (icon_name),
4203 (GDestroyNotify) xfree);
4204 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4205 NULL);
4206 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4207 NULL);
4208 }
4209 else if (img && old_img != img->pixmap)
4210 {
4211 (void) xg_get_image_for_pixmap (f, img, x->widget, wimage);
4212 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4213 (gpointer)img->pixmap);
4214
4215 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4216 NULL);
4217 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4218 NULL);
4219 }
4220
4221 gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
4222
4223 gtk_widget_set_sensitive (wbutton, enabled_p);
4224 }
4225 xg_show_toolbar_item (ti);
4226
4227 #undef PROP
4228 }
4229
4230 4231
4232 do
4233 {
4234 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i++);
4235 if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
4236 } while (ti != NULL);
4237
4238 new_req.height = 0;
4239 if (pack_tool_bar && f->n_tool_bar_items != 0)
4240 xg_pack_tool_bar (f);
4241
4242
4243 gtk_widget_size_request (GTK_WIDGET (wtoolbar), &new_req);
4244 if (old_req.height != new_req.height
4245 && ! FRAME_X_OUTPUT (f)->toolbar_detached)
4246 {
4247 FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
4248 xg_height_changed (f);
4249 }
4250 UNBLOCK_INPUT;
4251 }
4252
4253 4254
4255
4256 void
4257 free_frame_tool_bar (f)
4258 FRAME_PTR f;
4259 {
4260 struct x_output *x = f->output_data.x;
4261
4262 if (x->toolbar_widget)
4263 {
4264 int is_packed = x->handlebox_widget != 0;
4265 BLOCK_INPUT;
4266 4267
4268 if (is_packed)
4269 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4270 x->handlebox_widget);
4271 else
4272 gtk_widget_destroy (x->toolbar_widget);
4273
4274 x->toolbar_widget = 0;
4275 x->handlebox_widget = 0;
4276 FRAME_TOOLBAR_HEIGHT (f) = 0;
4277 xg_height_changed (f);
4278
4279 UNBLOCK_INPUT;
4280 }
4281 }
4282
4283
4284
4285 4286 4287
4288 void
4289 xg_initialize ()
4290 {
4291 GtkBindingSet *binding_set;
4292
4293 #if HAVE_XFT
4294 4295
4296 XftInit (0);
4297 #endif
4298
4299 gdpy_def = NULL;
4300 xg_ignore_gtk_scrollbar = 0;
4301 xg_detached_menus = 0;
4302 xg_menu_cb_list.prev = xg_menu_cb_list.next =
4303 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
4304
4305 id_to_widget.max_size = id_to_widget.used = 0;
4306 id_to_widget.widgets = 0;
4307
4308 4309 4310
4311 gtk_settings_set_string_property (gtk_settings_get_default (),
4312 "gtk-menu-bar-accel",
4313 "VoidSymbol",
4314 EMACS_CLASS);
4315
4316 4317
4318 gtk_settings_set_string_property (gtk_settings_get_default (),
4319 "gtk-key-theme-name",
4320 "Emacs",
4321 EMACS_CLASS);
4322
4323 4324
4325 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
4326 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4327 "close", 0);
4328
4329
4330 binding_set = gtk_binding_set_by_class (g_type_class_ref
4331 (GTK_TYPE_MENU_SHELL));
4332 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4333 "cancel", 0);
4334 }
4335
4336 #endif
4337
4338 4339