1 /* Functions for creating and updating GTK widgets.
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
29 #include "blockinput.h"
33 #include "termhooks.h"
34 #include <gdk/gdkkeysyms.h>
36 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
37 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
41 /***********************************************************************
43 ***********************************************************************/
44 /* The timer for scroll bar repetition and menu bar timeouts.
45 NULL if no timer is started. */
46 static struct atimer
*xg_timer
;
48 /* The cursor used for scroll bars and popup menus.
49 We only have one cursor for all scroll bars and all popup menus. */
50 static GdkCursor
*xg_left_ptr_cursor
;
53 /* The next two variables and functions are taken from lwlib. */
54 static widget_value
*widget_value_free_list
;
55 static int malloc_cpt
;
57 /* Allocate a widget_value structure, either by taking one from the
58 widget_value_free_list or by malloc:ing a new one.
60 Return a pointer to the allocated structure. */
62 malloc_widget_value ()
65 if (widget_value_free_list
)
67 wv
= widget_value_free_list
;
68 widget_value_free_list
= wv
->free_list
;
73 wv
= (widget_value
*) malloc (sizeof (widget_value
));
76 memset (wv
, 0, sizeof (widget_value
));
80 /* This is analogous to free. It frees only what was allocated
81 by malloc_widget_value, and no substructures. */
83 free_widget_value (wv
)
91 /* When the number of already allocated cells is too big,
98 wv
->free_list
= widget_value_free_list
;
99 widget_value_free_list
= wv
;
103 /* Set *CURSOR on W and all widgets W contain. We must do like this
104 for scroll bars and menu because they create widgets internally,
105 and it is those widgets that are visible.
107 If *CURSOR is NULL, create a GDK_LEFT_PTR cursor and set *CURSOR to
108 the created cursor. */
110 xg_set_cursor (w
, cursor
)
114 GList
*children
= gdk_window_peek_children (w
->window
);
116 /* Create the cursor unless already created. */
118 *cursor
= gdk_cursor_new (GDK_LEFT_PTR
);
120 gdk_window_set_cursor (w
->window
, *cursor
);
122 /* The scroll bar widget has more than one GDK window (had to look at
123 the source to figure this out), and there is no way to set cursor
124 on widgets in GTK. So we must set the cursor for all GDK windows.
127 for ( ; children
; children
= g_list_next (children
))
128 gdk_window_set_cursor (GDK_WINDOW (children
->data
), *cursor
);
131 /* Timer function called when a timeout occurs for xg_timer.
132 This function processes all GTK events in a recursive event loop.
133 This is done because GTK timer events are not seen by Emacs event
134 detection, Emacs only looks for X events. When a scroll bar has the
135 pointer (detected by button press/release events below) an Emacs
136 timer is started, and this function can then check if the GTK timer
137 has expired by calling the GTK event loop.
138 Also, when a menu is active, it has a small timeout before it
139 pops down the sub menu under it. */
141 xg_process_timeouts (timer
)
142 struct atimer
*timer
;
145 /* Ideally we would like to just handle timer events, like the Xt version
146 of this does in xterm.c, but there is no such feature in GTK. */
147 while (gtk_events_pending ())
148 gtk_main_iteration ();
152 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
153 xg_process_timeouts is called when the timer expires. The timer
154 started is continuous, i.e. runs until xg_stop_timer is called. */
161 EMACS_SET_SECS_USECS (interval
, 0, 100000);
162 xg_timer
= start_atimer (ATIMER_CONTINUOUS
,
169 /* Stop the xg_timer if started. */
175 cancel_atimer (xg_timer
);
180 /* Insert NODE into linked LIST. */
182 xg_list_insert (xg_list_node
*list
, xg_list_node
*node
)
184 xg_list_node
*list_start
= list
->next
;
186 if (list_start
) list_start
->prev
= node
;
187 node
->next
= list_start
;
192 /* Remove NODE from linked LIST. */
194 xg_list_remove (xg_list_node
*list
, xg_list_node
*node
)
196 xg_list_node
*list_start
= list
->next
;
197 if (node
== list_start
)
199 list
->next
= node
->next
;
200 if (list
->next
) list
->next
->prev
= 0;
204 node
->prev
->next
= node
->next
;
205 if (node
->next
) node
->next
->prev
= node
->prev
;
209 /* Allocate and return a utf8 version of STR. If STR is already
210 utf8 or NULL, just return STR.
211 If not, a new string is allocated and the caller must free the result
214 get_utf8_string (str
)
217 char *utf8_str
= str
;
219 /* If not UTF-8, try current locale. */
220 if (str
&& !g_utf8_validate (str
, -1, NULL
))
221 utf8_str
= g_locale_to_utf8 (str
, -1, 0, 0, 0);
228 /***********************************************************************
229 General functions for creating widgets, resizing, events, e.t.c.
230 ***********************************************************************/
232 /* Make a geometry string and pass that to GTK. It seems this is the
233 only way to get geometry position right if the user explicitly
234 asked for a position when starting Emacs.
235 F is the frame we shall set geometry for. */
240 if (f
->size_hint_flags
& USPosition
)
242 int left
= f
->left_pos
;
243 int xneg
= f
->size_hint_flags
& XNegative
;
244 int top
= f
->top_pos
;
245 int yneg
= f
->size_hint_flags
& YNegative
;
253 sprintf (geom_str
, "=%dx%d%c%d%c%d",
254 FRAME_PIXEL_WIDTH (f
),
255 FRAME_TOTAL_PIXEL_HEIGHT (f
),
256 (xneg
? '-' : '+'), left
,
257 (yneg
? '-' : '+'), top
);
259 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)),
261 fprintf (stderr
, "Failed to parse: '%s'\n", geom_str
);
266 /* Resize the outer window of frame F after chainging the height.
267 This happend when the menu bar or the tool bar is added or removed.
268 COLUMNS/ROWS is the size the edit area shall have after the resize. */
270 xg_resize_outer_widget (f
, columns
, rows
)
275 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)),
276 FRAME_PIXEL_WIDTH (f
), FRAME_TOTAL_PIXEL_HEIGHT (f
));
278 /* base_height is now changed. */
279 x_wm_set_size_hint (f
, 0, 0);
281 /* If we are not mapped yet, set geometry once again, as window
282 height now have changed. */
283 if (! GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f
)))
286 xg_frame_set_char_size (f
, columns
, rows
);
287 gdk_window_process_all_updates ();
290 /* This gets called after the frame F has been cleared. Since that is
291 done with X calls, we need to redraw GTK widget (scroll bars). */
296 GtkWidget
*w
= f
->output_data
.x
->widget
;
300 gtk_container_set_reallocate_redraws (GTK_CONTAINER (w
), TRUE
);
301 gtk_container_foreach (GTK_CONTAINER (w
),
302 (GtkCallback
) gtk_widget_queue_draw
,
304 gdk_window_process_all_updates ();
308 /* Function to handle resize of our widgets. Since Emacs has some layouts
309 that does not fit well with GTK standard containers, we do most layout
311 F is the frame to resize.
312 PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
314 xg_resize_widgets (f
, pixelwidth
, pixelheight
)
316 int pixelwidth
, pixelheight
;
318 int mbheight
= FRAME_MENUBAR_HEIGHT (f
);
319 int tbheight
= FRAME_TOOLBAR_HEIGHT (f
);
320 int rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, (pixelheight
321 - mbheight
- tbheight
));
322 int columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, pixelwidth
);
324 if (FRAME_GTK_WIDGET (f
)
325 && (columns
!= FRAME_COLS (f
) || rows
!= FRAME_LINES (f
)
326 || pixelwidth
!= FRAME_PIXEL_WIDTH (f
) || pixelheight
!= FRAME_PIXEL_HEIGHT (f
)))
328 struct x_output
*x
= f
->output_data
.x
;
331 all
.y
= mbheight
+ tbheight
;
334 all
.width
= pixelwidth
;
335 all
.height
= pixelheight
- mbheight
- tbheight
;
337 gtk_widget_size_allocate (x
->edit_widget
, &all
);
339 change_frame_size (f
, rows
, columns
, 0, 1, 0);
340 SET_FRAME_GARBAGED (f
);
341 cancel_mouse_face (f
);
346 /* Update our widget size to be COLS/ROWS characters for frame F. */
348 xg_frame_set_char_size (f
, cols
, rows
)
353 int pixelheight
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
)
354 + FRAME_MENUBAR_HEIGHT (f
) + FRAME_TOOLBAR_HEIGHT (f
);
357 /* Take into account the size of the scroll bar. Always use the
358 number of columns occupied by the scroll bar here otherwise we
359 might end up with a frame width that is not a multiple of the
360 frame's character width which is bad for vertically split
362 f
->scroll_bar_actual_width
363 = FRAME_SCROLL_BAR_COLS (f
) * FRAME_COLUMN_WIDTH (f
);
365 compute_fringe_widths (f
, 0);
367 /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
368 after calculating that value. */
369 pixelwidth
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, cols
);
371 /* Must resize our top level widget. Font size may have changed,
372 but not rows/cols. */
373 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)),
374 pixelwidth
, pixelheight
);
375 xg_resize_widgets (f
, pixelwidth
, pixelheight
);
377 SET_FRAME_GARBAGED (f
);
378 cancel_mouse_face (f
);
381 /* Convert an X Window WSESC to its corresponding GtkWidget.
382 Must be done like this, because GtkWidget:s can have "hidden"
383 X Window that aren't accessible.
385 Return 0 if no widget match WDESC. */
387 xg_win_to_widget (wdesc
)
391 GtkWidget
*gwdesc
= 0;
394 gdkwin
= gdk_xid_table_lookup (wdesc
);
398 event
.any
.window
= gdkwin
;
399 gwdesc
= gtk_get_event_widget (&event
);
406 /* Fill in the GdkColor C so that it represents PIXEL.
407 W is the widget that color will be used for. Used to find colormap. */
409 xg_pix_to_gcolor (w
, pixel
, c
)
414 GdkColormap
*map
= gtk_widget_get_colormap (w
);
415 gdk_colormap_query_color (map
, pixel
, c
);
418 /* Turning off double buffering for our GtkFixed widget has the side
419 effect of turning it off also for its children (scroll bars).
420 But we want those to be double buffered to not flicker so handle
421 expose manually here.
422 WIDGET is the GtkFixed widget that gets exposed.
423 EVENT is the expose event.
426 Return TRUE to tell GTK that this expose event has been fully handeled
427 and that GTK shall do nothing more with it. */
429 xg_fixed_handle_expose(GtkWidget
*widget
,
430 GdkEventExpose
*event
,
435 for (iter
= GTK_FIXED (widget
)->children
; iter
; iter
= g_list_next (iter
))
437 GtkFixedChild
*child_data
= (GtkFixedChild
*) iter
->data
;
438 GtkWidget
*child
= child_data
->widget
;
439 GdkWindow
*window
= child
->window
;
440 GdkRegion
*region
= gtk_widget_region_intersect (child
, event
->region
);
442 if (! gdk_region_empty (region
))
444 GdkEvent child_event
;
445 child_event
.expose
= *event
;
446 child_event
.expose
.region
= region
;
448 /* Turn on double buffering, i.e. draw to an off screen area. */
449 gdk_window_begin_paint_region (window
, region
);
451 /* Tell child to redraw itself. */
452 gdk_region_get_clipbox (region
, &child_event
.expose
.area
);
453 gtk_widget_send_expose (child
, &child_event
);
454 gdk_window_process_updates (window
, TRUE
);
456 /* Copy off screen area to the window. */
457 gdk_window_end_paint (window
);
460 gdk_region_destroy (region
);
466 /* Create and set up the GTK widgets for frame F.
467 Return 0 if creation failed, non-zero otherwise. */
469 xg_create_frame_widgets (f
)
482 wtop
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
483 wvbox
= gtk_vbox_new (FALSE
, 0);
484 wfixed
= gtk_fixed_new (); /* Must have this to place scroll bars */
486 if (! wtop
|| ! wvbox
|| ! wfixed
)
488 if (wtop
) gtk_widget_destroy (wtop
);
489 if (wvbox
) gtk_widget_destroy (wvbox
);
490 if (wfixed
) gtk_widget_destroy (wfixed
);
495 /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */
496 gtk_widget_set_name (wtop
, EMACS_CLASS
);
497 gtk_widget_set_name (wvbox
, "pane");
498 gtk_widget_set_name (wfixed
, SDATA (Vx_resource_name
));
500 /* If this frame has a title or name, set it in the title bar. */
501 if (! NILP (f
->title
)) title
= SDATA (f
->title
);
502 else if (! NILP (f
->name
)) title
= SDATA (f
->name
);
504 if (title
) gtk_window_set_title (GTK_WINDOW (wtop
), title
);
506 FRAME_GTK_OUTER_WIDGET (f
) = wtop
;
507 FRAME_GTK_WIDGET (f
) = wfixed
;
508 f
->output_data
.x
->vbox_widget
= wvbox
;
510 gtk_fixed_set_has_window (GTK_FIXED (wfixed
), TRUE
);
512 gtk_widget_set_size_request (wfixed
, FRAME_PIXEL_WIDTH (f
), FRAME_PIXEL_HEIGHT (f
));
514 gtk_container_add (GTK_CONTAINER (wtop
), wvbox
);
515 gtk_box_pack_end (GTK_BOX (wvbox
), wfixed
, TRUE
, TRUE
, 0);
517 if (FRAME_EXTERNAL_TOOL_BAR (f
))
518 update_frame_tool_bar (f
);
520 /* The tool bar is created but first there are no items in it.
521 This causes it to be zero height. Later items are added, but then
522 the frame is already mapped, so there is a "jumping" resize.
523 This makes geometry handling difficult, for example -0-0 will end
524 up in the wrong place as tool bar height has not been taken into account.
525 So we cheat a bit by setting a height that is what it will have
526 later on when tool bar items are added. */
527 if (FRAME_EXTERNAL_TOOL_BAR (f
) && FRAME_TOOLBAR_HEIGHT (f
) == 0)
528 FRAME_TOOLBAR_HEIGHT (f
) = 34;
531 /* We don't want this widget double buffered, because we draw on it
532 with regular X drawing primitives, so from a GTK/GDK point of
533 view, the widget is totally blank. When an expose comes, this
534 will make the widget blank, and then Emacs redraws it. This flickers
535 a lot, so we turn off double buffering. */
536 gtk_widget_set_double_buffered (wfixed
, FALSE
);
538 /* Turning off double buffering above has the side effect of turning
539 it off also for its children (scroll bars). But we want those
540 to be double buffered to not flicker so handle expose manually. */
541 g_signal_connect (G_OBJECT (wfixed
), "expose-event",
542 G_CALLBACK (xg_fixed_handle_expose
), 0);
544 /* GTK documents says use gtk_window_set_resizable. But then a user
545 can't shrink the window from its starting size. */
546 gtk_window_set_policy (GTK_WINDOW (wtop
), TRUE
, TRUE
, TRUE
);
547 gtk_window_set_wmclass (GTK_WINDOW (wtop
),
548 SDATA (Vx_resource_name
),
549 SDATA (Vx_resource_class
));
551 /* Add callback to do nothing on WM_DELETE_WINDOW. The default in
552 GTK is to destroy the widget. We want Emacs to do that instead. */
553 g_signal_connect (G_OBJECT (wtop
), "delete-event",
554 G_CALLBACK (gtk_true
), 0);
556 /* Convert our geometry parameters into a geometry string
558 GTK will itself handle calculating the real position this way. */
561 gtk_widget_add_events (wfixed
,
562 GDK_POINTER_MOTION_MASK
564 | GDK_BUTTON_PRESS_MASK
565 | GDK_BUTTON_RELEASE_MASK
567 | GDK_ENTER_NOTIFY_MASK
568 | GDK_LEAVE_NOTIFY_MASK
569 | GDK_FOCUS_CHANGE_MASK
571 | GDK_VISIBILITY_NOTIFY_MASK
);
573 /* Must realize the windows so the X window gets created. It is used
574 by callers of this function. */
575 gtk_widget_realize (wfixed
);
576 FRAME_X_WINDOW (f
) = GTK_WIDGET_TO_X_WIN (wfixed
);
578 /* Since GTK clears its window by filling with the background color,
579 we must keep X and GTK background in sync. */
580 xg_pix_to_gcolor (wfixed
, f
->output_data
.x
->background_pixel
, &bg
);
581 gtk_widget_modify_bg (wfixed
, GTK_STATE_NORMAL
, &bg
);
583 /* Also, do not let any background pixmap to be set, this looks very
584 bad as Emacs overwrites the background pixmap with its own idea
585 of background color. */
586 style
= gtk_widget_get_modifier_style (wfixed
);
588 /* Must use g_strdup because gtk_widget_modify_style does g_free. */
589 style
->bg_pixmap_name
[GTK_STATE_NORMAL
] = g_strdup ("<none>");
590 gtk_widget_modify_style (wfixed
, style
);
592 /* GTK does not set any border, and they look bad with GTK. */
594 f
->internal_border_width
= 0;
601 /* Set the normal size hints for the window manager, for frame F.
602 FLAGS is the flags word to use--or 0 meaning preserve the flags
603 that the window now has.
604 If USER_POSITION is nonzero, we set the User Position
605 flag (this is useful when FLAGS is 0). */
607 x_wm_set_size_hint (f
, flags
, user_position
)
612 if (FRAME_GTK_OUTER_WIDGET (f
))
614 /* Must use GTK routines here, otherwise GTK resets the size hints
615 to its own defaults. */
616 GdkGeometry size_hints
;
618 int base_width
, base_height
;
619 int min_rows
= 0, min_cols
= 0;
620 int win_gravity
= f
->win_gravity
;
624 memset (&size_hints
, 0, sizeof (size_hints
));
625 f
->output_data
.x
->size_hints
= size_hints
;
626 f
->output_data
.x
->hint_flags
= hint_flags
;
629 flags
= f
->size_hint_flags
;
631 size_hints
= f
->output_data
.x
->size_hints
;
632 hint_flags
= f
->output_data
.x
->hint_flags
;
634 hint_flags
|= GDK_HINT_RESIZE_INC
| GDK_HINT_MIN_SIZE
;
635 size_hints
.width_inc
= FRAME_COLUMN_WIDTH (f
);
636 size_hints
.height_inc
= FRAME_LINE_HEIGHT (f
);
638 hint_flags
|= GDK_HINT_BASE_SIZE
;
639 base_width
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, 0);
640 base_height
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, 0)
641 + FRAME_MENUBAR_HEIGHT (f
) + FRAME_TOOLBAR_HEIGHT (f
);
643 check_frame_size (f
, &min_rows
, &min_cols
);
645 size_hints
.base_width
= base_width
;
646 size_hints
.base_height
= base_height
;
647 size_hints
.min_width
= base_width
+ min_cols
* size_hints
.width_inc
;
648 size_hints
.min_height
= base_height
+ min_rows
* size_hints
.height_inc
;
651 /* These currently have a one to one mapping with the X values, but I
652 don't think we should rely on that. */
653 hint_flags
|= GDK_HINT_WIN_GRAVITY
;
654 size_hints
.win_gravity
= 0;
655 if (win_gravity
== NorthWestGravity
)
656 size_hints
.win_gravity
= GDK_GRAVITY_NORTH_WEST
;
657 else if (win_gravity
== NorthGravity
)
658 size_hints
.win_gravity
= GDK_GRAVITY_NORTH
;
659 else if (win_gravity
== NorthEastGravity
)
660 size_hints
.win_gravity
= GDK_GRAVITY_NORTH_EAST
;
661 else if (win_gravity
== WestGravity
)
662 size_hints
.win_gravity
= GDK_GRAVITY_WEST
;
663 else if (win_gravity
== CenterGravity
)
664 size_hints
.win_gravity
= GDK_GRAVITY_CENTER
;
665 else if (win_gravity
== EastGravity
)
666 size_hints
.win_gravity
= GDK_GRAVITY_EAST
;
667 else if (win_gravity
== SouthWestGravity
)
668 size_hints
.win_gravity
= GDK_GRAVITY_SOUTH_WEST
;
669 else if (win_gravity
== SouthGravity
)
670 size_hints
.win_gravity
= GDK_GRAVITY_SOUTH
;
671 else if (win_gravity
== SouthEastGravity
)
672 size_hints
.win_gravity
= GDK_GRAVITY_SOUTH_EAST
;
673 else if (win_gravity
== StaticGravity
)
674 size_hints
.win_gravity
= GDK_GRAVITY_STATIC
;
676 if (flags
& PPosition
) hint_flags
|= GDK_HINT_POS
;
677 if (flags
& USPosition
) hint_flags
|= GDK_HINT_USER_POS
;
678 if (flags
& USSize
) hint_flags
|= GDK_HINT_USER_SIZE
;
682 hint_flags
&= ~GDK_HINT_POS
;
683 hint_flags
|= GDK_HINT_USER_POS
;
688 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)),
689 FRAME_GTK_OUTER_WIDGET (f
),
693 f
->output_data
.x
->size_hints
= size_hints
;
694 f
->output_data
.x
->hint_flags
= hint_flags
;
699 /* Change background color of a frame.
700 Since GTK uses the background colour to clear the window, we must
701 keep the GTK and X colors in sync.
702 F is the frame to change,
703 BG is the pixel value to change to. */
705 xg_set_background_color (f
, bg
)
709 if (FRAME_GTK_WIDGET (f
))
714 xg_pix_to_gcolor (FRAME_GTK_WIDGET (f
), bg
, &gdk_bg
);
715 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f
), GTK_STATE_NORMAL
, &gdk_bg
);
722 /***********************************************************************
724 ***********************************************************************/
725 /* Return the dialog title to use for a dialog of type KEY.
726 This is the encoding used by lwlib. We use the same for GTK. */
728 get_dialog_title (char key
)
738 title
= "Information";
757 /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
758 the dialog, but return TRUE so the event does not propagate further
759 in GTK. This prevents GTK from destroying the dialog widget automatically
760 and we can always destrou the widget manually, regardles of how
761 it was popped down (button press or WM_DELETE_WINDOW).
762 W is the dialog widget.
763 EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
764 user_data is NULL (not used).
766 Returns TRUE to end propagation of event. */
768 dialog_delete_callback (w
, event
, user_data
)
773 gtk_widget_unmap (w
);
777 /* Create a popup dialog window. See also xg_create_widget below.
778 WV is a widget_value describing the dialog.
779 SELECT_CB is the callback to use when a button has been pressed.
780 DEACTIVATE_CB is the callback to use when the dialog pops down.
782 Returns the GTK dialog widget. */
784 create_dialog (wv
, select_cb
, deactivate_cb
)
787 GCallback deactivate_cb
;
789 char *title
= get_dialog_title (wv
->name
[0]);
790 int total_buttons
= wv
->name
[1] - '0';
791 int right_buttons
= wv
->name
[4] - '0';
794 int button_spacing
= 10;
795 GtkWidget
*wdialog
= gtk_dialog_new ();
800 GtkWidget
*whbox_down
;
802 /* If the number of buttons is greater than 4, make two rows of buttons
803 instead. This looks better. */
804 int make_two_rows
= total_buttons
> 4;
806 if (right_buttons
== 0) right_buttons
= total_buttons
/2;
807 left_buttons
= total_buttons
- right_buttons
;
809 gtk_window_set_title (GTK_WINDOW (wdialog
), title
);
810 gtk_widget_set_name (wdialog
, "emacs-dialog");
812 cur_box
= GTK_BOX (GTK_DIALOG (wdialog
)->action_area
);
816 wvbox
= gtk_vbox_new (TRUE
, button_spacing
);
817 whbox_up
= gtk_hbox_new (FALSE
, 0);
818 whbox_down
= gtk_hbox_new (FALSE
, 0);
820 gtk_box_pack_start (cur_box
, wvbox
, FALSE
, FALSE
, 0);
821 gtk_box_pack_start (GTK_BOX (wvbox
), whbox_up
, FALSE
, FALSE
, 0);
822 gtk_box_pack_start (GTK_BOX (wvbox
), whbox_down
, FALSE
, FALSE
, 0);
824 cur_box
= GTK_BOX (whbox_up
);
827 g_signal_connect (G_OBJECT (wdialog
), "delete-event",
828 G_CALLBACK (dialog_delete_callback
), 0);
832 g_signal_connect (G_OBJECT (wdialog
), "close", deactivate_cb
, 0);
833 g_signal_connect (G_OBJECT (wdialog
), "response", deactivate_cb
, 0);
836 for (item
= wv
->contents
; item
; item
= item
->next
)
838 char *utf8_label
= get_utf8_string (item
->value
);
842 if (item
->name
&& strcmp (item
->name
, "message") == 0)
844 /* This is the text part of the dialog. */
845 w
= gtk_label_new (utf8_label
);
846 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog
)->vbox
),
849 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog
)->vbox
), w
,
851 gtk_misc_set_alignment (GTK_MISC (w
), 0.1, 0.5);
853 /* Try to make dialog look better. Must realize first so
854 the widget can calculate the size it needs. */
855 gtk_widget_realize (w
);
856 gtk_widget_size_request (w
, &req
);
857 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog
)->vbox
),
859 if (item
->value
&& strlen (item
->value
) > 0)
860 button_spacing
= 2*req
.width
/strlen (item
->value
);
864 /* This is one button to add to the dialog. */
865 w
= gtk_button_new_with_label (utf8_label
);
867 gtk_widget_set_sensitive (w
, FALSE
);
869 g_signal_connect (G_OBJECT (w
), "clicked",
870 select_cb
, item
->call_data
);
872 gtk_box_pack_start (cur_box
, w
, TRUE
, TRUE
, button_spacing
);
873 if (++button_nr
== left_buttons
)
876 cur_box
= GTK_BOX (whbox_down
);
878 gtk_box_pack_start (cur_box
,
885 if (utf8_label
&& utf8_label
!= item
->value
)
901 /* Callback function invoked when the Ok button is pressed in
903 W is the file dialog widget,
904 ARG points to an integer where we record what has happend. */
906 xg_file_sel_ok (w
, arg
)
910 *(int*)arg
= XG_FILE_OK
;
913 /* Callback function invoked when the Cancel button is pressed in
915 W is the file dialog widget,
916 ARG points to an integer where we record what has happend. */
918 xg_file_sel_cancel (w
, arg
)
922 *(int*)arg
= XG_FILE_CANCEL
;
925 /* Callback function invoked when the file dialog is destroyed (i.e.
926 popped down). We must keep track of this, because if this
927 happens, GTK destroys the widget. But if for example, Ok is pressed,
928 the dialog is popped down, but the dialog widget is not destroyed.
929 W is the file dialog widget,
930 ARG points to an integer where we record what has happend. */
932 xg_file_sel_destroy (w
, arg
)
936 *(int*)arg
= XG_FILE_DESTROYED
;
939 /* Read a file name from the user using a file dialog.
940 F is the current frame.
941 PROMPT is a prompt to show to the user. May not be NULL.
942 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
943 If MUSTMATCH_P is non-zero, the returned file name must be an existing
946 Returns a file name or NULL if no file was selected.
947 The returned string must be freed by the caller. */
949 xg_get_file_name (f
, prompt
, default_filename
, mustmatch_p
)
952 char *default_filename
;
956 GtkFileSelection
*filesel
;
957 int filesel_done
= XG_FILE_NOT_DONE
;
960 filewin
= gtk_file_selection_new (prompt
);
961 filesel
= GTK_FILE_SELECTION (filewin
);
963 gtk_widget_set_name (filewin
, "emacs-filedialog");
965 gtk_window_set_transient_for (GTK_WINDOW (filewin
),
966 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)));
967 gtk_window_set_destroy_with_parent (GTK_WINDOW (filewin
), TRUE
);
969 g_signal_connect (G_OBJECT (filesel
->ok_button
),
971 G_CALLBACK (xg_file_sel_ok
),
973 g_signal_connect (G_OBJECT (filesel
->cancel_button
),
975 G_CALLBACK (xg_file_sel_cancel
),
977 g_signal_connect (G_OBJECT (filesel
),
979 G_CALLBACK (xg_file_sel_destroy
),
982 if (default_filename
)
983 gtk_file_selection_set_filename (filesel
, default_filename
);
987 /* The selection_entry part of filesel is not documented. */
988 gtk_widget_set_sensitive (filesel
->selection_entry
, FALSE
);
989 gtk_file_selection_hide_fileop_buttons (filesel
);
993 gtk_widget_show_all (filewin
);
995 while (filesel_done
== XG_FILE_NOT_DONE
)
996 gtk_main_iteration ();
998 if (filesel_done
== XG_FILE_OK
)
999 fn
= xstrdup ((char*) gtk_file_selection_get_filename (filesel
));
1001 if (filesel_done
!= XG_FILE_DESTROYED
)
1002 gtk_widget_destroy (filewin
);
1008 /***********************************************************************
1010 ***********************************************************************/
1012 /* The name of menu items that can be used for citomization. Since GTK
1013 RC files are very crude and primitive, we have to set this on all
1014 menu item names so a user can easily cutomize menu items. */
1016 #define MENU_ITEM_NAME "emacs-menuitem"
1019 /* Linked list of all allocated struct xg_menu_cb_data. Used for marking
1020 during GC. The next member points to the items. */
1021 static xg_list_node xg_menu_cb_list
;
1023 /* Linked list of all allocated struct xg_menu_item_cb_data. Used for marking
1024 during GC. The next member points to the items. */
1025 static xg_list_node xg_menu_item_cb_list
;
1027 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
1028 F is the frame CL_DATA will be initialized for.
1029 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1031 The menu bar and all sub menus under the menu bar in a frame
1032 share the same structure, hence the reference count.
1034 Returns CL_DATA if CL_DATA is not NULL, or a pointer to a newly
1035 allocated xg_menu_cb_data if CL_DATA is NULL. */
1036 static xg_menu_cb_data
*
1037 make_cl_data (cl_data
, f
, highlight_cb
)
1038 xg_menu_cb_data
*cl_data
;
1040 GCallback highlight_cb
;
1044 cl_data
= (xg_menu_cb_data
*) xmalloc (sizeof (*cl_data
));
1046 cl_data
->menu_bar_vector
= f
->menu_bar_vector
;
1047 cl_data
->menu_bar_items_used
= f
->menu_bar_items_used
;
1048 cl_data
->highlight_cb
= highlight_cb
;
1049 cl_data
->ref_count
= 0;
1051 xg_list_insert (&xg_menu_cb_list
, &cl_data
->ptrs
);
1054 cl_data
->ref_count
++;
1059 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
1060 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1062 When the menu bar is updated, menu items may have been added and/or
1063 removed, so menu_bar_vector and menu_bar_items_used change. We must
1064 then update CL_DATA since it is used to determine which menu
1065 item that is invoked in the menu.
1066 HIGHLIGHT_CB could change, there is no check that the same
1067 function is given when modifying a menu bar as was given when
1068 creating the menu bar. */
1070 update_cl_data (cl_data
, f
, highlight_cb
)
1071 xg_menu_cb_data
*cl_data
;
1073 GCallback highlight_cb
;
1078 cl_data
->menu_bar_vector
= f
->menu_bar_vector
;
1079 cl_data
->menu_bar_items_used
= f
->menu_bar_items_used
;
1080 cl_data
->highlight_cb
= highlight_cb
;
1084 /* Decrease reference count for CL_DATA.
1085 If reference count is zero, free CL_DATA. */
1087 unref_cl_data (cl_data
)
1088 xg_menu_cb_data
*cl_data
;
1090 if (cl_data
&& cl_data
->ref_count
> 0)
1092 cl_data
->ref_count
--;
1093 if (cl_data
->ref_count
== 0)
1095 xg_list_remove (&xg_menu_cb_list
, &cl_data
->ptrs
);
1101 /* Function that marks all lisp data during GC. */
1107 for (iter
= xg_menu_cb_list
.next
; iter
; iter
= iter
->next
)
1108 mark_object (&((xg_menu_cb_data
*) iter
)->menu_bar_vector
);
1110 for (iter
= xg_menu_item_cb_list
.next
; iter
; iter
= iter
->next
)
1112 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) iter
;
1114 if (! NILP (cb_data
->help
))
1115 mark_object (&cb_data
->help
);
1120 /* Callback called when a menu item is destroyed. Used to free data.
1121 W is the widget that is being destroyed (not used).
1122 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
1124 menuitem_destroy_callback (w
, client_data
)
1126 gpointer client_data
;
1130 xg_menu_item_cb_data
*data
= (xg_menu_item_cb_data
*) client_data
;
1131 xg_list_remove (&xg_menu_item_cb_list
, &data
->ptrs
);
1136 /* Callback called when the pointer enters/leaves a menu item.
1138 EVENT is either an enter event or leave event.
1139 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.
1141 Returns FALSE to tell GTK to keep processing this event. */
1143 menuitem_highlight_callback (w
, event
, client_data
)
1145 GdkEventCrossing
*event
;
1146 gpointer client_data
;
1150 xg_menu_item_cb_data
*data
= (xg_menu_item_cb_data
*) client_data
;
1151 gpointer call_data
= event
->type
== GDK_LEAVE_NOTIFY
? 0 : client_data
;
1153 if (! NILP (data
->help
) && data
->cl_data
->highlight_cb
)
1155 GtkCallback func
= (GtkCallback
) data
->cl_data
->highlight_cb
;
1156 (*func
) (w
, call_data
);
1163 /* Callback called when a menu is destroyed. Used to free data.
1164 W is the widget that is being destroyed (not used).
1165 CLIENT_DATA points to the xg_menu_cb_data associated with W. */
1167 menu_destroy_callback (w
, client_data
)
1169 gpointer client_data
;
1171 unref_cl_data ((xg_menu_cb_data
*) client_data
);
1174 /* Callback called when a menu does a grab or ungrab. That means the
1175 menu has been activated or deactivated.
1176 Used to start a timer so the small timeout the menus in GTK uses before
1177 popping down a menu is seen by Emacs (see xg_process_timeouts above).
1178 W is the widget that does the grab (not used).
1179 UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
1180 CLIENT_DATA is NULL (not used). */
1182 menu_grab_callback (GtkWidget
*widget
,
1184 gpointer client_data
)
1186 /* Keep track of total number of grabs. */
1189 if (ungrab_p
) cnt
--;
1192 if (cnt
> 0 && ! xg_timer
) xg_start_timer ();
1193 else if (cnt
== 0 && xg_timer
) xg_stop_timer ();
1196 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
1197 must be non-NULL) and can be inserted into a menu item.
1199 Returns the GtkHBox. */
1201 make_widget_for_menu_item (utf8_label
, utf8_key
)
1209 wbox
= gtk_hbox_new (FALSE
, 0);
1210 wlbl
= gtk_label_new (utf8_label
);
1211 wkey
= gtk_label_new (utf8_key
);
1213 gtk_misc_set_alignment (GTK_MISC (wlbl
), 0.0, 0.5);
1214 gtk_misc_set_alignment (GTK_MISC (wkey
), 0.0, 0.5);
1216 gtk_box_pack_start (GTK_BOX (wbox
), wlbl
, TRUE
, TRUE
, 0);
1217 gtk_box_pack_start (GTK_BOX (wbox
), wkey
, FALSE
, FALSE
, 0);
1219 gtk_widget_set_name (wlbl
, MENU_ITEM_NAME
);
1220 gtk_widget_set_name (wkey
, MENU_ITEM_NAME
);
1221 gtk_widget_set_name (wbox
, MENU_ITEM_NAME
);
1226 /* Make and return a menu item widget with the key to the right.
1227 UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
1228 UTF8_KEY is the text representing the key binding.
1229 ITEM is the widget_value describing the menu item.
1231 GROUP is an in/out parameter. If the menu item to be created is not
1232 part of any radio menu group, *GROUP contains NULL on entry and exit.
1233 If the menu item to be created is part of a radio menu group, on entry
1234 *GROUP contains the group to use, or NULL if this is the first item
1235 in the group. On exit, *GROUP contains the radio item group.
1237 Unfortunately, keys don't line up as nicely as in Motif,
1238 but the MacOS X version doesn't either, so I guess that is OK. */
1240 make_menu_item (utf8_label
, utf8_key
, item
, group
)
1247 GtkWidget
*wtoadd
= 0;
1250 wtoadd
= make_widget_for_menu_item (utf8_label
, utf8_key
);
1252 if (item
->button_type
== BUTTON_TYPE_TOGGLE
)
1255 if (utf8_key
) w
= gtk_check_menu_item_new ();
1256 else w
= gtk_check_menu_item_new_with_label (utf8_label
);
1257 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w
), item
->selected
);
1259 else if (item
->button_type
== BUTTON_TYPE_RADIO
)
1261 if (utf8_key
) w
= gtk_radio_menu_item_new (*group
);
1262 else w
= gtk_radio_menu_item_new_with_label (*group
, utf8_label
);
1263 *group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w
));
1265 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w
), TRUE
);
1270 if (utf8_key
) w
= gtk_menu_item_new ();
1271 else w
= gtk_menu_item_new_with_label (utf8_label
);
1274 if (wtoadd
) gtk_container_add (GTK_CONTAINER (w
), wtoadd
);
1275 if (! item
->enabled
) gtk_widget_set_sensitive (w
, FALSE
);
1280 /* Return non-zero if LABEL specifies a separator (GTK only has one
1283 xg_separator_p (char *label
)
1285 if (! label
) return 0;
1286 else if (strlen (label
) > 3
1287 && strncmp (label
, "--", 2) == 0
1290 static char* separator_names
[] = {
1295 "single-dashed-line",
1296 "double-dashed-line",
1298 "shadow-etched-out",
1299 "shadow-etched-in-dash",
1300 "shadow-etched-out-dash",
1301 "shadow-double-etched-in",
1302 "shadow-double-etched-out",
1303 "shadow-double-etched-in-dash",
1304 "shadow-double-etched-out-dash",
1311 for (i
= 0; separator_names
[i
]; ++i
)
1312 if (strcmp (label
, separator_names
[i
]) == 0)
1317 /* Old-style separator, maybe. It's a separator if it contains
1319 while (*label
== '-')
1321 if (*label
== 0) return 1;
1327 GtkWidget
*xg_did_tearoff
;
1329 /* Callback invoked when a detached menu window is removed. Here we
1330 delete the popup menu.
1331 WIDGET is the top level window that is removed (the parent of the menu).
1332 EVENT is the event that triggers the window removal.
1333 CLIENT_DATA points to the menu that is detached.
1335 Returns TRUE to tell GTK to stop processing this event. */
1337 tearoff_remove (widget
, event
, client_data
)
1340 gpointer client_data
;
1342 gtk_widget_destroy (GTK_WIDGET (client_data
));
1346 /* Callback invoked when a menu is detached. It sets the xg_did_tearoff
1348 WIDGET is the GtkTearoffMenuItem.
1349 CLIENT_DATA is not used. */
1351 tearoff_activate (widget
, client_data
)
1353 gpointer client_data
;
1355 GtkWidget
*menu
= gtk_widget_get_parent (widget
);
1356 if (! gtk_menu_get_tearoff_state (GTK_MENU (menu
)))
1359 xg_did_tearoff
= menu
;
1362 /* If a detach of a popup menu is done, this function should be called
1363 to keep the menu around until the detached window is removed.
1364 MENU is the top level menu for the popup,
1365 SUBMENU is the menu that got detached (that is MENU or a
1366 submenu of MENU), see the xg_did_tearoff variable. */
1368 xg_keep_popup (menu
, submenu
)
1374 /* Find the top widget for the detached menu. */
1375 p
= gtk_widget_get_toplevel (submenu
);
1377 /* Delay destroying the menu until the detached menu is removed. */
1378 g_signal_connect (G_OBJECT (p
), "unmap_event",
1379 G_CALLBACK (tearoff_remove
), menu
);
1382 /* Create a menu item widget, and connect the callbacks.
1383 ITEM decribes the menu item.
1384 F is the frame the created menu belongs to.
1385 SELECT_CB is the callback to use when a menu item is selected.
1386 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1387 CL_DATA points to the callback data to be used for this menu.
1388 GROUP is an in/out parameter. If the menu item to be created is not
1389 part of any radio menu group, *GROUP contains NULL on entry and exit.
1390 If the menu item to be created is part of a radio menu group, on entry
1391 *GROUP contains the group to use, or NULL if this is the first item
1392 in the group. On exit, *GROUP contains the radio item group.
1394 Returns the created GtkWidget. */
1396 xg_create_one_menuitem (item
, f
, select_cb
, highlight_cb
, cl_data
, group
)
1399 GCallback select_cb
;
1400 GCallback highlight_cb
;
1401 xg_menu_cb_data
*cl_data
;
1407 xg_menu_item_cb_data
*cb_data
;
1409 utf8_label
= get_utf8_string (item
->name
);
1410 utf8_key
= get_utf8_string (item
->key
);
1412 w
= make_menu_item (utf8_label
, utf8_key
, item
, group
);
1414 if (utf8_label
&& utf8_label
!= item
->name
) g_free (utf8_label
);
1415 if (utf8_key
&& utf8_key
!= item
->key
) g_free (utf8_key
);
1417 cb_data
= xmalloc (sizeof (xg_menu_item_cb_data
));
1419 xg_list_insert (&xg_menu_item_cb_list
, &cb_data
->ptrs
);
1421 cb_data
->unhighlight_id
= cb_data
->highlight_id
= cb_data
->select_id
= 0;
1422 cb_data
->help
= item
->help
;
1423 cb_data
->cl_data
= cl_data
;
1424 cb_data
->call_data
= item
->call_data
;
1426 g_signal_connect (G_OBJECT (w
),
1428 G_CALLBACK (menuitem_destroy_callback
),
1431 /* Put cb_data in widget, so we can get at it when modifying menubar */
1432 g_object_set_data (G_OBJECT (w
), XG_ITEM_DATA
, cb_data
);
1434 /* final item, not a submenu */
1435 if (item
->call_data
&& ! item
->contents
)
1439 = g_signal_connect (G_OBJECT (w
), "activate", select_cb
, cb_data
);
1442 if (! NILP (item
->help
) && highlight_cb
)
1444 /* We use enter/leave notify instead of select/deselect because
1445 select/deselect doesn't go well with detached menus. */
1446 cb_data
->highlight_id
1447 = g_signal_connect (G_OBJECT (w
),
1448 "enter-notify-event",
1449 G_CALLBACK (menuitem_highlight_callback
),
1451 cb_data
->unhighlight_id
1452 = g_signal_connect (G_OBJECT (w
),
1453 "leave-notify-event",
1454 G_CALLBACK (menuitem_highlight_callback
),
1461 static GtkWidget
*create_menus
P_ ((widget_value
*, FRAME_PTR
, GCallback
,
1462 GCallback
, GCallback
, int, int, int,
1463 GtkWidget
*, xg_menu_cb_data
*, char *));
1465 /* Create a full menu tree specified by DATA.
1466 F is the frame the created menu belongs to.
1467 SELECT_CB is the callback to use when a menu item is selected.
1468 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
1469 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1470 POP_UP_P is non-zero if we shall create a popup menu.
1471 MENU_BAR_P is non-zero if we shall create a menu bar.
1472 ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
1473 if MENU_BAR_P is non-zero.
1474 TOPMENU is the topmost GtkWidget that others shall be placed under.
1475 It may be NULL, in that case we create the appropriate widget
1476 (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
1477 CL_DATA is the callback data we shall use for this menu, or NULL
1478 if we haven't set the first callback yet.
1479 NAME is the name to give to the top level menu if this function
1480 creates it. May be NULL to not set any name.
1482 Returns the top level GtkWidget. This is TOPLEVEL if TOPLEVEL is
1485 This function calls itself to create submenus. */
1488 create_menus (data
, f
, select_cb
, deactivate_cb
, highlight_cb
,
1489 pop_up_p
, menu_bar_p
, add_tearoff_p
, topmenu
, cl_data
, name
)
1492 GCallback select_cb
;
1493 GCallback deactivate_cb
;
1494 GCallback highlight_cb
;
1499 xg_menu_cb_data
*cl_data
;
1503 GtkWidget
*wmenu
= topmenu
;
1504 GSList
*group
= NULL
;
1508 if (! menu_bar_p
) wmenu
= gtk_menu_new ();
1509 else wmenu
= gtk_menu_bar_new ();
1511 /* Put cl_data on the top menu for easier access. */
1512 cl_data
= make_cl_data (cl_data
, f
, highlight_cb
);
1513 g_object_set_data (G_OBJECT (wmenu
), XG_FRAME_DATA
, (gpointer
)cl_data
);
1514 g_signal_connect (G_OBJECT (wmenu
), "destroy",
1515 G_CALLBACK (menu_destroy_callback
), cl_data
);
1518 gtk_widget_set_name (wmenu
, name
);
1521 g_signal_connect (G_OBJECT (wmenu
),
1522 "deactivate", deactivate_cb
, 0);
1524 g_signal_connect (G_OBJECT (wmenu
),
1525 "grab-notify", G_CALLBACK (menu_grab_callback
), 0);
1528 if (! menu_bar_p
&& add_tearoff_p
)
1530 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new ();
1531 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu
), tearoff
);
1533 g_signal_connect (G_OBJECT (tearoff
), "activate",
1534 G_CALLBACK (tearoff_activate
), 0);
1537 for (item
= data
; item
; item
= item
->next
)
1541 if (pop_up_p
&& !item
->contents
&& !item
->call_data
1542 && !xg_separator_p (item
->name
))
1545 /* A title for a popup. We do the same as GTK does when
1546 creating titles, but it does not look good. */
1548 utf8_label
= get_utf8_string (item
->name
);
1550 gtk_menu_set_title (GTK_MENU (wmenu
), utf8_label
);
1551 w
= gtk_menu_item_new_with_label (utf8_label
);
1552 gtk_widget_set_sensitive (w
, FALSE
);
1553 if (utf8_label
&& utf8_label
!= item
->name
) g_free (utf8_label
);
1555 else if (xg_separator_p (item
->name
))
1558 /* GTK only have one separator type. */
1559 w
= gtk_separator_menu_item_new ();
1563 w
= xg_create_one_menuitem (item
,
1565 item
->contents
? 0 : select_cb
,
1572 GtkWidget
*submenu
= create_menus (item
->contents
,
1583 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w
), submenu
);
1587 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu
), w
);
1588 gtk_widget_set_name (w
, MENU_ITEM_NAME
);
1594 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
1595 TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
1596 with some text and buttons.
1597 F is the frame the created item belongs to.
1598 NAME is the name to use for the top widget.
1599 VAL is a widget_value structure describing items to be created.
1600 SELECT_CB is the callback to use when a menu item is selected or
1601 a dialog button is pressed.
1602 DEACTIVATE_CB is the callback to use when an item is deactivated.
1603 For a menu, when a sub menu is not shown anymore, for a dialog it is
1604 called when the dialog is popped down.
1605 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1607 Returns the widget created. */
1609 xg_create_widget (type
, name
, f
, val
,
1610 select_cb
, deactivate_cb
, highlight_cb
)
1615 GCallback select_cb
;
1616 GCallback deactivate_cb
;
1617 GCallback highlight_cb
;
1620 if (strcmp (type
, "dialog") == 0)
1622 w
= create_dialog (val
, select_cb
, deactivate_cb
);
1623 gtk_window_set_transient_for (GTK_WINDOW (w
),
1624 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f
)));
1625 gtk_window_set_destroy_with_parent (GTK_WINDOW (w
), TRUE
);
1628 gtk_widget_set_name (w
, "emacs-dialog");
1630 else if (strcmp (type
, "menubar") == 0 || strcmp (type
, "popup") == 0)
1632 w
= create_menus (val
->contents
,
1637 strcmp (type
, "popup") == 0,
1638 strcmp (type
, "menubar") == 0,
1644 /* Set the cursor to an arrow for popup menus when they are mapped.
1645 This is done by default for menu bar menus. */
1646 if (strcmp (type
, "popup") == 0)
1648 /* Must realize so the GdkWindow inside the widget is created. */
1649 gtk_widget_realize (w
);
1650 xg_set_cursor (w
, &xg_left_ptr_cursor
);
1655 fprintf (stderr
, "bad type in xg_create_widget: %s, doing nothing\n",
1662 /* Return the label for menu item WITEM. */
1664 xg_get_menu_item_label (witem
)
1667 GtkLabel
*wlabel
= GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem
)));
1668 return gtk_label_get_label (wlabel
);
1671 /* Return non-zero if the menu item WITEM has the text LABEL. */
1673 xg_item_label_same_p (witem
, label
)
1678 char *utf8_label
= get_utf8_string (label
);
1679 const char *old_label
= witem
? xg_get_menu_item_label (witem
) : 0;
1681 if (! old_label
&& ! utf8_label
)
1683 else if (old_label
&& utf8_label
)
1684 is_same
= strcmp (utf8_label
, old_label
) == 0;
1686 if (utf8_label
&& utf8_label
!= label
) g_free (utf8_label
);
1691 /* Remove widgets in LIST from container WCONT. */
1693 remove_from_container (wcont
, list
)
1699 for (iter
= list
; iter
; iter
= g_list_next (iter
))
1701 GtkWidget
*w
= GTK_WIDGET (iter
->data
);
1703 /* Add a ref to w so we can explicitly destroy it later. */
1705 gtk_container_remove (GTK_CONTAINER (wcont
), w
);
1707 /* If there is a menu under this widget that has been detached,
1708 there is a reference to it, and just removing w from the
1709 container does not destroy the submenu. By explicitly
1710 destroying w we make sure the submenu is destroyed, thus
1711 removing the detached window also if there was one. */
1712 gtk_widget_destroy (w
);
1716 /* Update the top level names in MENUBAR (i.e. not submenus).
1717 F is the frame the menu bar belongs to.
1718 *LIST is a list with the current menu bar names (menu item widgets).
1719 ITER is the item within *LIST that shall be updated.
1720 POS is the numerical position, starting at 0, of ITER in *LIST.
1721 VAL describes what the menu bar shall look like after the update.
1722 SELECT_CB is the callback to use when a menu item is selected.
1723 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1724 CL_DATA points to the callback data to be used for this menu bar.
1726 This function calls itself to walk through the menu bar names. */
1728 xg_update_menubar (menubar
, f
, list
, iter
, pos
, val
,
1729 select_cb
, highlight_cb
, cl_data
)
1736 GCallback select_cb
;
1737 GCallback highlight_cb
;
1738 xg_menu_cb_data
*cl_data
;
1740 if (! iter
&& ! val
)
1742 else if (iter
&& ! val
)
1744 /* Item(s) have been removed. Remove all remaining items. */
1745 remove_from_container (menubar
, iter
);
1751 else if (! iter
&& val
)
1753 /* Item(s) added. Add all new items in one call. */
1754 create_menus (val
, f
, select_cb
, 0, highlight_cb
,
1755 0, 1, 0, menubar
, cl_data
, 0);
1761 /* Below this neither iter or val is NULL */
1762 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter
->data
), val
->name
))
1764 /* This item is still the same, check next item. */
1766 iter
= g_list_next (iter
);
1769 else /* This item is changed. */
1771 GtkMenuItem
*witem
= GTK_MENU_ITEM (iter
->data
);
1772 GtkMenuItem
*witem2
= 0;
1773 int val_in_menubar
= 0;
1774 int iter_in_new_menubar
= 0;
1778 /* See if the changed entry (val) is present later in the menu bar */
1780 iter2
&& ! val_in_menubar
;
1781 iter2
= g_list_next (iter2
))
1783 witem2
= GTK_MENU_ITEM (iter2
->data
);
1784 val_in_menubar
= xg_item_label_same_p (witem2
, val
->name
);
1787 /* See if the current entry (iter) is present later in the
1788 specification for the new menu bar. */
1789 for (cur
= val
; cur
&& ! iter_in_new_menubar
; cur
= cur
->next
)
1790 iter_in_new_menubar
= xg_item_label_same_p (witem
, cur
->name
);
1792 if (val_in_menubar
&& ! iter_in_new_menubar
)
1796 /* This corresponds to:
1801 gtk_widget_ref (GTK_WIDGET (witem
));
1802 gtk_container_remove (GTK_CONTAINER (menubar
), GTK_WIDGET (witem
));
1803 gtk_widget_destroy (GTK_WIDGET (witem
));
1805 /* Must get new list since the old changed. */
1806 g_list_free (*list
);
1807 *list
= iter
= gtk_container_get_children (GTK_CONTAINER (menubar
));
1808 while (nr
-- > 0) iter
= g_list_next (iter
);
1810 else if (! val_in_menubar
&& ! iter_in_new_menubar
)
1812 /* This corresponds to:
1815 Rename B to X. This might seem to be a strange thing to do,
1816 since if there is a menu under B it will be totally wrong for X.
1817 But consider editing a C file. Then there is a C-mode menu
1818 (corresponds to B above).
1819 If then doing C-x C-f the minibuf menu (X above) replaces the
1820 C-mode menu. When returning from the minibuffer, we get
1821 back the C-mode menu. Thus we do:
1822 Rename B to X (C-mode to minibuf menu)
1823 Rename X to B (minibuf to C-mode menu).
1824 If the X menu hasn't been invoked, the menu under B
1825 is up to date when leaving the minibuffer. */
1826 GtkLabel
*wlabel
= GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem
)));
1827 char *utf8_label
= get_utf8_string (val
->name
);
1829 gtk_label_set_text (wlabel
, utf8_label
);
1831 iter
= g_list_next (iter
);
1835 else if (! val_in_menubar
&& iter_in_new_menubar
)
1837 /* This corresponds to:
1844 GtkWidget
*w
= xg_create_one_menuitem (val
,
1851 gtk_widget_set_name (w
, MENU_ITEM_NAME
);
1852 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar
), w
, pos
);
1854 g_list_free (*list
);
1855 *list
= iter
= gtk_container_get_children (GTK_CONTAINER (menubar
));
1856 while (nr
-- > 0) iter
= g_list_next (iter
);
1857 iter
= g_list_next (iter
);
1861 else /* if (val_in_menubar && iter_in_new_menubar) */
1864 /* This corresponds to:
1869 gtk_widget_ref (GTK_WIDGET (witem2
));
1870 gtk_container_remove (GTK_CONTAINER (menubar
), GTK_WIDGET (witem2
));
1871 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar
),
1872 GTK_WIDGET (witem2
), pos
);
1873 gtk_widget_unref (GTK_WIDGET (witem2
));
1875 g_list_free (*list
);
1876 *list
= iter
= gtk_container_get_children (GTK_CONTAINER (menubar
));
1877 while (nr
-- > 0) iter
= g_list_next (iter
);
1883 /* Update the rest of the menu bar. */
1884 xg_update_menubar (menubar
, f
, list
, iter
, pos
, val
,
1885 select_cb
, highlight_cb
, cl_data
);
1888 /* Update the menu item W so it corresponds to VAL.
1889 SELECT_CB is the callback to use when a menu item is selected.
1890 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1891 CL_DATA is the data to set in the widget for menu invokation. */
1893 xg_update_menu_item (val
, w
, select_cb
, highlight_cb
, cl_data
)
1896 GCallback select_cb
;
1897 GCallback highlight_cb
;
1898 xg_menu_cb_data
*cl_data
;
1905 const char *old_label
= 0;
1906 const char *old_key
= 0;
1907 xg_menu_item_cb_data
*cb_data
;
1909 wchild
= gtk_bin_get_child (GTK_BIN (w
));
1910 utf8_label
= get_utf8_string (val
->name
);
1911 utf8_key
= get_utf8_string (val
->key
);
1913 /* See if W is a menu item with a key. See make_menu_item above. */
1914 if (GTK_IS_HBOX (wchild
))
1916 GList
*list
= gtk_container_get_children (GTK_CONTAINER (wchild
));
1918 wlbl
= GTK_LABEL (list
->data
);
1919 wkey
= GTK_LABEL (list
->next
->data
);
1924 /* Remove the key and keep just the label. */
1925 gtk_widget_ref (GTK_WIDGET (wlbl
));
1926 gtk_container_remove (GTK_CONTAINER (w
), wchild
);
1927 gtk_container_add (GTK_CONTAINER (w
), GTK_WIDGET (wlbl
));
1932 else /* Just a label. */
1934 wlbl
= GTK_LABEL (wchild
);
1936 /* Check if there is now a key. */
1939 GtkWidget
*wtoadd
= make_widget_for_menu_item (utf8_label
, utf8_key
);
1940 GList
*list
= gtk_container_get_children (GTK_CONTAINER (wtoadd
));
1942 wlbl
= GTK_LABEL (list
->data
);
1943 wkey
= GTK_LABEL (list
->next
->data
);
1946 gtk_container_remove (GTK_CONTAINER (w
), wchild
);
1947 gtk_container_add (GTK_CONTAINER (w
), wtoadd
);
1952 if (wkey
) old_key
= gtk_label_get_label (wkey
);
1953 if (wlbl
) old_label
= gtk_label_get_label (wlbl
);
1955 if (wkey
&& utf8_key
&& (! old_key
|| strcmp (utf8_key
, old_key
) != 0))
1956 gtk_label_set_text (wkey
, utf8_key
);
1958 if (! old_label
|| strcmp (utf8_label
, old_label
) != 0)
1959 gtk_label_set_text (wlbl
, utf8_label
);
1961 if (utf8_key
&& utf8_key
!= val
->key
) g_free (utf8_key
);
1962 if (utf8_label
&& utf8_label
!= val
->name
) g_free (utf8_label
);
1964 if (! val
->enabled
&& GTK_WIDGET_SENSITIVE (w
))
1965 gtk_widget_set_sensitive (w
, FALSE
);
1966 else if (val
->enabled
&& ! GTK_WIDGET_SENSITIVE (w
))
1967 gtk_widget_set_sensitive (w
, TRUE
);
1969 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (w
),
1973 cb_data
->call_data
= val
->call_data
;
1974 cb_data
->help
= val
->help
;
1975 cb_data
->cl_data
= cl_data
;
1977 /* We assume the callback functions don't change. */
1978 if (val
->call_data
&& ! val
->contents
)
1980 /* This item shall have a select callback. */
1981 if (! cb_data
->select_id
)
1983 = g_signal_connect (G_OBJECT (w
), "activate",
1984 select_cb
, cb_data
);
1986 else if (cb_data
->select_id
)
1988 g_signal_handler_disconnect (w
, cb_data
->select_id
);
1989 cb_data
->select_id
= 0;
1992 if (NILP (cb_data
->help
))
1994 /* Shall not have help. Remove if any existed previously. */
1995 if (cb_data
->highlight_id
)
1997 g_signal_handler_disconnect (G_OBJECT (w
),
1998 cb_data
->highlight_id
);
1999 cb_data
->highlight_id
= 0;
2001 if (cb_data
->unhighlight_id
)
2003 g_signal_handler_disconnect (G_OBJECT (w
),
2004 cb_data
->unhighlight_id
);
2005 cb_data
->unhighlight_id
= 0;
2008 else if (! cb_data
->highlight_id
&& highlight_cb
)
2010 /* Have help now, but didn't previously. Add callback. */
2011 cb_data
->highlight_id
2012 = g_signal_connect (G_OBJECT (w
),
2013 "enter-notify-event",
2014 G_CALLBACK (menuitem_highlight_callback
),
2016 cb_data
->unhighlight_id
2017 = g_signal_connect (G_OBJECT (w
),
2018 "leave-notify-event",
2019 G_CALLBACK (menuitem_highlight_callback
),
2025 /* Update the toggle menu item W so it corresponds to VAL. */
2027 xg_update_toggle_item (val
, w
)
2031 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w
), val
->selected
);
2034 /* Update the radio menu item W so it corresponds to VAL. */
2036 xg_update_radio_item (val
, w
)
2040 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w
), val
->selected
);
2043 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
2044 SUBMENU may be NULL, in that case a new menu is created.
2045 F is the frame the menu bar belongs to.
2046 VAL describes the contents of the menu bar.
2047 SELECT_CB is the callback to use when a menu item is selected.
2048 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2049 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2050 CL_DATA is the call back data to use for any newly created items.
2052 Returns the updated submenu widget, that is SUBMENU unless SUBMENU
2056 xg_update_submenu (submenu
, f
, val
,
2057 select_cb
, deactivate_cb
, highlight_cb
, cl_data
)
2061 GCallback select_cb
;
2062 GCallback deactivate_cb
;
2063 GCallback highlight_cb
;
2064 xg_menu_cb_data
*cl_data
;
2066 GtkWidget
*newsub
= submenu
;
2070 int has_tearoff_p
= 0;
2071 GList
*first_radio
= 0;
2074 list
= gtk_container_get_children (GTK_CONTAINER (submenu
));
2076 for (cur
= val
, iter
= list
;
2078 iter
= g_list_next (iter
), cur
= cur
->next
)
2080 GtkWidget
*w
= GTK_WIDGET (iter
->data
);
2082 /* Skip tearoff items, they have no counterpart in val. */
2083 if (GTK_IS_TEAROFF_MENU_ITEM (w
))
2086 iter
= g_list_next (iter
);
2087 if (iter
) w
= GTK_WIDGET (iter
->data
);
2091 /* Remember first radio button in a group. If we get a mismatch in
2092 a radio group we must rebuild the whole group so that the connections
2093 in GTK becomes correct. */
2094 if (cur
->button_type
== BUTTON_TYPE_RADIO
&& ! first_radio
)
2096 else if (cur
->button_type
!= BUTTON_TYPE_RADIO
2097 && ! GTK_IS_RADIO_MENU_ITEM (w
))
2100 if (GTK_IS_SEPARATOR_MENU_ITEM (w
))
2102 if (! xg_separator_p (cur
->name
))
2105 else if (GTK_IS_CHECK_MENU_ITEM (w
))
2107 if (cur
->button_type
!= BUTTON_TYPE_TOGGLE
)
2109 xg_update_toggle_item (cur
, w
);
2110 xg_update_menu_item (cur
, w
, select_cb
, highlight_cb
, cl_data
);
2112 else if (GTK_IS_RADIO_MENU_ITEM (w
))
2114 if (cur
->button_type
!= BUTTON_TYPE_RADIO
)
2116 xg_update_radio_item (cur
, w
);
2117 xg_update_menu_item (cur
, w
, select_cb
, highlight_cb
, cl_data
);
2119 else if (GTK_IS_MENU_ITEM (w
))
2121 GtkMenuItem
*witem
= GTK_MENU_ITEM (w
);
2124 if (cur
->button_type
!= BUTTON_TYPE_NONE
||
2125 xg_separator_p (cur
->name
))
2128 xg_update_menu_item (cur
, w
, select_cb
, highlight_cb
, cl_data
);
2130 sub
= gtk_menu_item_get_submenu (witem
);
2131 if (sub
&& ! cur
->contents
)
2133 /* Not a submenu anymore. */
2134 gtk_widget_ref (sub
);
2135 gtk_menu_item_remove_submenu (witem
);
2136 gtk_widget_destroy (sub
);
2138 else if (cur
->contents
)
2142 nsub
= xg_update_submenu (sub
, f
, cur
->contents
,
2143 select_cb
, deactivate_cb
,
2144 highlight_cb
, cl_data
);
2146 /* If this item just became a submenu, we must set it. */
2148 gtk_menu_item_set_submenu (witem
, nsub
);
2153 /* Structural difference. Remove everything from here and down
2159 /* Remove widgets from first structual change. */
2162 /* If we are adding new menu items below, we must remove from
2163 first radio button so that radio groups become correct. */
2164 if (cur
&& first_radio
) remove_from_container (submenu
, first_radio
);
2165 else remove_from_container (submenu
, iter
);
2170 /* More items added. Create them. */
2171 newsub
= create_menus (cur
,
2184 if (list
) g_list_free (list
);
2189 /* Update the MENUBAR.
2190 F is the frame the menu bar belongs to.
2191 VAL describes the contents of the menu bar.
2192 If DEEP_P is non-zero, rebuild all but the top level menu names in
2193 the MENUBAR. If DEEP_P is zero, just rebuild the names in the menubar.
2194 SELECT_CB is the callback to use when a menu item is selected.
2195 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2196 HIGHLIGHT_CB is the callback to call when entering/leaving menu items. */
2198 xg_modify_menubar_widgets (menubar
, f
, val
, deep_p
,
2199 select_cb
, deactivate_cb
, highlight_cb
)
2204 GCallback select_cb
;
2205 GCallback deactivate_cb
;
2206 GCallback highlight_cb
;
2208 xg_menu_cb_data
*cl_data
;
2209 GList
*list
= gtk_container_get_children (GTK_CONTAINER (menubar
));
2213 cl_data
= (xg_menu_cb_data
*) g_object_get_data (G_OBJECT (menubar
),
2218 widget_value
*cur
= val
->contents
;
2219 xg_update_menubar (menubar
, f
, &list
, list
, 0, cur
,
2220 select_cb
, highlight_cb
, cl_data
);
2226 /* Update all sub menus.
2227 We must keep the submenu names (GTK menu item widgets) since the
2228 X Window in the XEvent that activates the menu are those widgets. */
2230 /* Update cl_data, menu_item things in F may have changed. */
2231 update_cl_data (cl_data
, f
, highlight_cb
);
2233 for (cur
= val
->contents
; cur
; cur
= cur
->next
)
2240 /* Find sub menu that corresponds to val and update it. */
2241 for (iter
= list
; iter
; iter
= g_list_next (iter
))
2243 witem
= GTK_MENU_ITEM (iter
->data
);
2244 if (xg_item_label_same_p (witem
, cur
->name
))
2246 sub
= gtk_menu_item_get_submenu (witem
);
2251 newsub
= xg_update_submenu (sub
,
2258 /* sub may still be NULL. If we just updated non deep and added
2259 a new menu bar item, it has no sub menu yet. So we set the
2260 newly created sub menu under witem. */
2262 gtk_menu_item_set_submenu (witem
, newsub
);
2268 gtk_widget_show_all (menubar
);
2271 /* Recompute all the widgets of frame F, when the menu bar has been
2272 changed. Value is non-zero if widgets were updated. */
2275 xg_update_frame_menubar (f
)
2278 struct x_output
*x
= f
->output_data
.x
;
2281 if (!x
->menubar_widget
|| GTK_WIDGET_MAPPED (x
->menubar_widget
))
2286 gtk_box_pack_start (GTK_BOX (x
->vbox_widget
), x
->menubar_widget
,
2288 gtk_box_reorder_child (GTK_BOX (x
->vbox_widget
), x
->menubar_widget
, 0);
2290 gtk_widget_show_all (x
->menubar_widget
);
2291 gtk_widget_size_request (x
->menubar_widget
, &req
);
2293 FRAME_MENUBAR_HEIGHT (f
) = req
.height
;
2295 /* The height has changed, resize outer widget and set columns
2296 rows to what we had before adding the menu bar. */
2297 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
2299 SET_FRAME_GARBAGED (f
);
2305 /* Get rid of the menu bar of frame F, and free its storage.
2306 This is used when deleting a frame, and when turning off the menu bar. */
2309 free_frame_menubar (f
)
2312 struct x_output
*x
= f
->output_data
.x
;
2314 if (x
->menubar_widget
)
2318 gtk_container_remove (GTK_CONTAINER (x
->vbox_widget
), x
->menubar_widget
);
2319 /* The menubar and its children shall be deleted when removed from
2321 x
->menubar_widget
= 0;
2322 FRAME_MENUBAR_HEIGHT (f
) = 0;
2324 /* The height has changed, resize outer widget and set columns
2325 rows to what we had before removing the menu bar. */
2326 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
2328 SET_FRAME_GARBAGED (f
);
2335 /***********************************************************************
2336 Scroll bar functions
2337 ***********************************************************************/
2340 /* Setting scroll bar values invokes the callback. Use this variable
2341 to indicate that callback should do nothing. */
2342 int xg_ignore_gtk_scrollbar
;
2344 /* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
2345 32 bits. But we want to store pointers, and they may be larger
2346 than 32 bits. Keep a mapping from integer index to widget pointers
2347 to get around the 32 bit limitation. */
2350 GtkWidget
**widgets
;
2355 /* Grow this much every time we need to allocate more */
2356 #define ID_TO_WIDGET_INCR 32
2358 /* Store the widget pointer W in id_to_widget and return the integer index. */
2360 xg_store_widget_in_map (w
)
2365 if (id_to_widget
.max_size
== id_to_widget
.used
)
2367 int new_size
= id_to_widget
.max_size
+ ID_TO_WIDGET_INCR
;
2369 id_to_widget
.widgets
= xrealloc (id_to_widget
.widgets
,
2370 sizeof (GtkWidget
*)*new_size
);
2372 for (i
= id_to_widget
.max_size
; i
< new_size
; ++i
)
2373 id_to_widget
.widgets
[i
] = 0;
2374 id_to_widget
.max_size
= new_size
;
2377 /* Just loop over the array and find a free place. After all,
2378 how many scroll bars are we creating? Should be a small number.
2379 The check above guarantees we will find a free place. */
2380 for (i
= 0; i
< id_to_widget
.max_size
; ++i
)
2382 if (! id_to_widget
.widgets
[i
])
2384 id_to_widget
.widgets
[i
] = w
;
2385 ++id_to_widget
.used
;
2391 /* Should never end up here */
2395 /* Remove pointer at IDX from id_to_widget.
2396 Called when scroll bar is destroyed. */
2398 xg_remove_widget_from_map (idx
)
2401 if (idx
< id_to_widget
.max_size
&& id_to_widget
.widgets
[idx
] != 0)
2403 id_to_widget
.widgets
[idx
] = 0;
2404 --id_to_widget
.used
;
2408 /* Get the widget pointer at IDX from id_to_widget. */
2410 xg_get_widget_from_map (idx
)
2413 if (idx
< id_to_widget
.max_size
&& id_to_widget
.widgets
[idx
] != 0)
2414 return id_to_widget
.widgets
[idx
];
2419 /* Return the scrollbar id for X Window WID.
2420 Return -1 if WID not in id_to_widget. */
2422 xg_get_scroll_id_for_window (wid
)
2428 w
= xg_win_to_widget (wid
);
2432 for (idx
= 0; idx
< id_to_widget
.max_size
; ++idx
)
2433 if (id_to_widget
.widgets
[idx
] == w
)
2440 /* Callback invoked when scroll bar WIDGET is destroyed.
2441 DATA is the index into id_to_widget for WIDGET.
2442 We free pointer to last scroll bar values here and remove the index. */
2444 xg_gtk_scroll_destroy (widget
, data
)
2451 p
= g_object_get_data (G_OBJECT (widget
), XG_LAST_SB_DATA
);
2453 xg_remove_widget_from_map (id
);
2456 /* Callback for button press/release events. Used to start timer so that
2457 the scroll bar repetition timer in GTK gets handeled.
2458 Also, sets bar->dragging to Qnil when dragging (button release) is done.
2459 WIDGET is the scroll bar widget the event is for (not used).
2460 EVENT contains the event.
2461 USER_DATA points to the struct scrollbar structure.
2463 Returns FALSE to tell GTK that it shall continue propagate the event
2466 scroll_bar_button_cb (widget
, event
, user_data
)
2468 GdkEventButton
*event
;
2471 if (event
->type
== GDK_BUTTON_PRESS
&& ! xg_timer
)
2473 else if (event
->type
== GDK_BUTTON_RELEASE
)
2475 struct scroll_bar
*bar
= (struct scroll_bar
*) user_data
;
2476 if (xg_timer
) xg_stop_timer ();
2477 bar
->dragging
= Qnil
;
2483 /* Create a scroll bar widget for frame F. Store the scroll bar
2485 SCROLL_CALLBACK is the callback to invoke when the value of the
2487 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
2488 to set resources for the widget. */
2490 xg_create_scroll_bar (f
, bar
, scroll_callback
, scroll_bar_name
)
2492 struct scroll_bar
*bar
;
2493 GCallback scroll_callback
;
2494 char *scroll_bar_name
;
2500 /* Page, step increment values are not so important here, they
2501 will be corrected in x_set_toolkit_scroll_bar_thumb. */
2502 vadj
= gtk_adjustment_new (XG_SB_MIN
, XG_SB_MIN
, XG_SB_MAX
,
2505 wscroll
= gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj
));
2506 gtk_widget_set_name (wscroll
, scroll_bar_name
);
2507 gtk_range_set_update_policy (GTK_RANGE (wscroll
), GTK_UPDATE_CONTINUOUS
);
2509 scroll_id
= xg_store_widget_in_map (wscroll
);
2511 g_signal_connect (G_OBJECT (wscroll
),
2515 g_signal_connect (G_OBJECT (wscroll
),
2517 G_CALLBACK (xg_gtk_scroll_destroy
),
2518 (gpointer
) scroll_id
);
2520 /* Connect to button press and button release to detect if any scroll bar
2522 g_signal_connect (G_OBJECT (wscroll
),
2523 "button-press-event",
2524 G_CALLBACK (scroll_bar_button_cb
),
2526 g_signal_connect (G_OBJECT (wscroll
),
2527 "button-release-event",
2528 G_CALLBACK (scroll_bar_button_cb
),
2531 gtk_fixed_put (GTK_FIXED (f
->output_data
.x
->edit_widget
),
2534 /* Set the cursor to an arrow. */
2535 xg_set_cursor (wscroll
, &xg_left_ptr_cursor
);
2537 SET_SCROLL_BAR_X_WINDOW (bar
, scroll_id
);
2540 /* Make the scroll bar represented by SCROLLBAR_ID visible. */
2542 xg_show_scroll_bar (scrollbar_id
)
2545 GtkWidget
*w
= xg_get_widget_from_map (scrollbar_id
);
2547 gtk_widget_show (w
);
2550 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
2552 xg_remove_scroll_bar (f
, scrollbar_id
)
2556 GtkWidget
*w
= xg_get_widget_from_map (scrollbar_id
);
2559 gtk_widget_destroy (w
);
2560 SET_FRAME_GARBAGED (f
);
2564 /* Find left/top for widget W in GtkFixed widget WFIXED. */
2566 xg_find_top_left_in_fixed (w
, wfixed
, left
, top
)
2567 GtkWidget
*w
, *wfixed
;
2572 for (iter
= GTK_FIXED (wfixed
)->children
; iter
; iter
= g_list_next (iter
))
2574 GtkFixedChild
*child
= (GtkFixedChild
*) iter
->data
;
2576 if (child
->widget
== w
)
2584 /* Shall never end up here. */
2588 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
2590 TOP/LEFT are the new pixel positions where the bar shall appear.
2591 WIDTH, HEIGHT is the size in pixels the bar shall have. */
2593 xg_update_scrollbar_pos (f
, scrollbar_id
, top
, left
, width
, height
,
2594 real_left
, canon_width
)
2603 GtkWidget
*wscroll
= xg_get_widget_from_map (scrollbar_id
);
2607 GtkWidget
*wfixed
= f
->output_data
.x
->edit_widget
;
2608 int winextra
= canon_width
> width
? (canon_width
- width
) / 2 : 0;
2609 int bottom
= top
+ height
;
2612 int oldtop
, oldleft
, oldbottom
;
2615 /* Get old values. */
2616 xg_find_top_left_in_fixed (wscroll
, wfixed
, &oldleft
, &oldtop
);
2617 gtk_widget_size_request (wscroll
, &req
);
2618 oldbottom
= oldtop
+ req
.height
;
2620 /* Scroll bars in GTK has a fixed width, so if we say width 16, it
2621 will only be its fixed width (14 is default) anyway, the rest is
2622 blank. We are drawing the mode line across scroll bars when
2630 When we "unsplit" the frame:
2639 the remains of the mode line can be seen in these blank spaces.
2640 So we must clear them explicitly.
2641 GTK scroll bars should do that, but they don't.
2642 Also, the canonical width may be wider than the width for the
2643 scroll bar so that there is some space (typically 1 pixel) between
2644 the scroll bar and the edge of the window and between the scroll
2645 bar and the fringe. */
2647 if (oldtop
!= -1 && oldleft
!= -1)
2649 int gtkextral
, gtkextrah
;
2650 int xl
, xr
, wbl
, wbr
;
2651 int bottomdiff
, topdiff
;
2653 gtk_widget_style_get (wscroll
, "slider_width", &slider_width
, NULL
);
2654 gtkextral
= width
> slider_width
? (width
- slider_width
) / 2 : 0;
2655 gtkextrah
= gtkextral
? (width
- slider_width
- gtkextral
) : 0;
2658 wbl
= gtkextral
+ winextra
;
2659 wbr
= gtkextrah
+ winextra
;
2660 xr
= left
+ gtkextral
+ slider_width
;
2661 bottomdiff
= abs (oldbottom
- bottom
);
2662 topdiff
= abs (oldtop
- top
);
2664 if (oldleft
!= left
)
2666 gdk_window_clear_area (wfixed
->window
, xl
, top
, wbl
, height
);
2667 gdk_window_clear_area (wfixed
->window
, xr
, top
, wbr
, height
);
2672 gdk_window_clear_area (wfixed
->window
, xl
, top
, wbl
, topdiff
);
2673 gdk_window_clear_area (wfixed
->window
, xr
, top
, wbr
, topdiff
);
2675 else if (oldtop
< top
)
2677 gdk_window_clear_area (wfixed
->window
, xl
, oldtop
, wbl
, topdiff
);
2678 gdk_window_clear_area (wfixed
->window
, xr
, oldtop
, wbr
, topdiff
);
2681 if (oldbottom
> bottom
)
2683 gdk_window_clear_area (wfixed
->window
, xl
, bottom
, wbl
,
2685 gdk_window_clear_area (wfixed
->window
, xr
, bottom
, wbr
,
2688 else if (oldbottom
< bottom
)
2690 gdk_window_clear_area (wfixed
->window
, xl
, oldbottom
, wbl
,
2692 gdk_window_clear_area (wfixed
->window
, xr
, oldbottom
, wbr
,
2697 /* Move and resize to new values. */
2698 gtk_fixed_move (GTK_FIXED (wfixed
), wscroll
, left
, top
);
2699 gtk_widget_set_size_request (wscroll
, width
, height
);
2701 /* Must force out update so changed scroll bars gets redrawn. */
2702 gdk_window_process_all_updates ();
2704 SET_FRAME_GARBAGED (f
);
2705 cancel_mouse_face (f
);
2709 /* Set the thumb size and position of scroll bar BAR. We are currently
2710 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2712 xg_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2713 struct scroll_bar
*bar
;
2714 int portion
, position
, whole
;
2716 GtkWidget
*wscroll
= xg_get_widget_from_map (SCROLL_BAR_X_WINDOW (bar
));
2718 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2720 if (wscroll
&& NILP (bar
->dragging
))
2729 adj
= gtk_range_get_adjustment (GTK_RANGE (wscroll
));
2731 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
2732 rather than the real portion value. This makes the thumb less likely
2733 to resize and that looks better. */
2734 portion
= WINDOW_TOTAL_LINES (XWINDOW (bar
->window
)) * 30;
2735 /* When the thumb is at the bottom, position == whole.
2736 So we need to increase `whole' to make space for the thumb. */
2743 top
= (gdouble
) position
/ whole
;
2744 shown
= (gdouble
) portion
/ whole
;
2747 size
= shown
* XG_SB_RANGE
;
2748 size
= min (size
, XG_SB_RANGE
);
2749 size
= max (size
, 1);
2751 value
= top
* XG_SB_RANGE
;
2752 value
= min (value
, XG_SB_MAX
- size
);
2753 value
= max (value
, XG_SB_MIN
);
2755 /* Assume all lines are of equal size. */
2756 new_step
= size
/ max (1, FRAME_LINES (f
));
2758 if ((int) adj
->page_size
!= size
2759 || (int) adj
->step_increment
!= new_step
)
2761 adj
->page_size
= size
;
2762 adj
->step_increment
= new_step
;
2763 /* Assume a page increment is about 95% of the page size */
2764 adj
->page_increment
= (int) (0.95*adj
->page_size
);
2768 if (changed
|| (int) gtk_range_get_value (GTK_RANGE (wscroll
)) != value
)
2770 GtkWidget
*wfixed
= f
->output_data
.x
->edit_widget
;
2774 /* gtk_range_set_value invokes the callback. Set
2775 ignore_gtk_scrollbar to make the callback do nothing */
2776 xg_ignore_gtk_scrollbar
= 1;
2778 if ((int) gtk_range_get_value (GTK_RANGE (wscroll
)) != value
)
2779 gtk_range_set_value (GTK_RANGE (wscroll
), (gdouble
)value
);
2781 gtk_adjustment_changed (adj
);
2783 xg_ignore_gtk_scrollbar
= 0;
2791 /***********************************************************************
2793 ***********************************************************************/
2794 /* The key for the data we put in the GtkImage widgets. The data is
2795 the image used by Emacs. We use this to see if we need to update
2796 the GtkImage with a new image. */
2797 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
2799 /* Callback function invoked when a tool bar item is pressed.
2800 W is the button widget in the tool bar that got pressed,
2801 CLIENT_DATA is an integer that is the index of the button in the
2802 tool bar. 0 is the first button. */
2804 xg_tool_bar_callback (w
, client_data
)
2806 gpointer client_data
;
2808 int idx
= (int)client_data
;
2809 FRAME_PTR f
= (FRAME_PTR
) g_object_get_data (G_OBJECT (w
), XG_FRAME_DATA
);
2810 Lisp_Object key
, frame
;
2811 struct input_event event
;
2813 if (! f
|| ! f
->n_tool_bar_items
|| NILP (f
->tool_bar_items
))
2816 idx
*= TOOL_BAR_ITEM_NSLOTS
;
2818 key
= AREF (f
->tool_bar_items
, idx
+ TOOL_BAR_ITEM_KEY
);
2819 XSETFRAME (frame
, f
);
2820 event
.kind
= TOOL_BAR_EVENT
;
2821 event
.frame_or_window
= frame
;
2823 kbd_buffer_store_event (&event
);
2825 event
.kind
= TOOL_BAR_EVENT
;
2826 event
.frame_or_window
= frame
;
2828 event
.modifiers
= 0; /* These are not available. */
2829 kbd_buffer_store_event (&event
);
2832 /* This callback is called when a tool bar is detached. We must set
2833 the height of the tool bar to zero when this happens so frame sizes
2834 are correctly calculated.
2835 WBOX is the handle box widget that enables detach/attach of the tool bar.
2836 W is the tool bar widget.
2837 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
2839 xg_tool_bar_detach_callback (wbox
, w
, client_data
)
2842 gpointer client_data
;
2844 FRAME_PTR f
= (FRAME_PTR
) client_data
;
2848 /* When detaching a tool bar, not everything dissapear. There are
2849 a few pixels left that are used to drop the tool bar back into
2851 int bw
= gtk_container_get_border_width (GTK_CONTAINER (wbox
));
2852 FRAME_TOOLBAR_HEIGHT (f
) = 2;
2854 /* The height has changed, resize outer widget and set columns
2855 rows to what we had before detaching the tool bar. */
2856 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
2860 /* This callback is called when a tool bar is reattached. We must set
2861 the height of the tool bar when this happens so frame sizes
2862 are correctly calculated.
2863 WBOX is the handle box widget that enables detach/attach of the tool bar.
2864 W is the tool bar widget.
2865 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
2867 xg_tool_bar_attach_callback (wbox
, w
, client_data
)
2870 gpointer client_data
;
2872 FRAME_PTR f
= (FRAME_PTR
) client_data
;
2878 gtk_widget_size_request (w
, &req
);
2879 FRAME_TOOLBAR_HEIGHT (f
) = req
.height
;
2881 /* The height has changed, resize outer widget and set columns
2882 rows to what we had before detaching the tool bar. */
2883 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
2887 /* This callback is called when the mouse enters or leaves a tool bar item.
2888 It is used for displaying and hiding the help text.
2889 W is the tool bar item, a button.
2890 EVENT is either an enter event or leave event.
2891 CLIENT_DATA is an integer that is the index of the button in the
2892 tool bar. 0 is the first button.
2894 Returns FALSE to tell GTK to keep processing this event. */
2896 xg_tool_bar_help_callback (w
, event
, client_data
)
2898 GdkEventCrossing
*event
;
2899 gpointer client_data
;
2901 int idx
= (int)client_data
;
2902 FRAME_PTR f
= (FRAME_PTR
) g_object_get_data (G_OBJECT (w
), XG_FRAME_DATA
);
2903 Lisp_Object help
, frame
;
2905 if (! GTK_IS_BUTTON (w
))
2910 if (! f
|| ! f
->n_tool_bar_items
|| NILP (f
->tool_bar_items
))
2913 if (event
->type
== GDK_ENTER_NOTIFY
)
2915 idx
*= TOOL_BAR_ITEM_NSLOTS
;
2916 help
= AREF (f
->tool_bar_items
, idx
+ TOOL_BAR_ITEM_HELP
);
2919 help
= AREF (f
->tool_bar_items
, idx
+ TOOL_BAR_ITEM_CAPTION
);
2924 XSETFRAME (frame
, f
);
2925 kbd_buffer_store_help_event (frame
, help
);
2931 /* This callback is called when a tool bar item shall be redrawn.
2932 It modifies the expose event so that the GtkImage widget redraws the
2933 whole image. This to overcome a bug that makes GtkImage draw the image
2934 in the wrong place when it tries to redraw just a part of the image.
2935 W is the GtkImage to be redrawn.
2936 EVENT is the expose event for W.
2937 CLIENT_DATA is unused.
2939 Returns FALSE to tell GTK to keep processing this event. */
2941 xg_tool_bar_item_expose_callback (w
, event
, client_data
)
2943 GdkEventExpose
*event
;
2944 gpointer client_data
;
2948 gdk_drawable_get_size (event
->window
, &width
, &height
);
2950 event
->area
.x
-= width
> event
->area
.width
? width
-event
->area
.width
: 0;
2951 event
->area
.y
-= height
> event
->area
.height
? height
-event
->area
.height
: 0;
2953 event
->area
.x
= max(0, event
->area
.x
);
2954 event
->area
.y
= max(0, event
->area
.y
);
2956 event
->area
.width
= max (width
, event
->area
.width
);
2957 event
->area
.height
= max (height
, event
->area
.height
);
2962 /* This callback is called when a tool bar shall be redrawn.
2963 We need to update the tool bar from here in case the image cache
2964 has deleted the pixmaps used in the tool bar.
2965 W is the GtkToolbar to be redrawn.
2966 EVENT is the expose event for W.
2967 CLIENT_DATA is pointing to the frame for this tool bar.
2969 Returns FALSE to tell GTK to keep processing this event. */
2971 xg_tool_bar_expose_callback (w
, event
, client_data
)
2973 GdkEventExpose
*event
;
2974 gpointer client_data
;
2976 update_frame_tool_bar((FRAME_PTR
)client_data
);
2981 xg_create_tool_bar (f
)
2984 struct x_output
*x
= f
->output_data
.x
;
2986 int vbox_pos
= x
->menubar_widget
? 1 : 0;
2988 x
->toolbar_widget
= gtk_toolbar_new ();
2989 x
->handlebox_widget
= gtk_handle_box_new ();
2990 gtk_container_add (GTK_CONTAINER (x
->handlebox_widget
),
2993 gtk_box_pack_start (GTK_BOX (x
->vbox_widget
), x
->handlebox_widget
,
2996 gtk_box_reorder_child (GTK_BOX (x
->vbox_widget
), x
->handlebox_widget
,
2999 gtk_widget_set_name (x
->toolbar_widget
, "emacs-toolbar");
3001 /* We only have icons, so override any user setting. We could
3002 use the caption property of the toolbar item (see update_frame_tool_bar
3003 below), but some of those strings are long, making the toolbar so
3004 long it does not fit on the screen. The GtkToolbar widget makes every
3005 item equal size, so the longest caption determine the size of every
3006 tool bar item. I think the creators of the GtkToolbar widget
3007 counted on 4 or 5 character long strings. */
3008 gtk_toolbar_set_style (GTK_TOOLBAR (x
->toolbar_widget
), GTK_TOOLBAR_ICONS
);
3009 gtk_toolbar_set_orientation (GTK_TOOLBAR (x
->toolbar_widget
),
3010 GTK_ORIENTATION_HORIZONTAL
);
3012 g_signal_connect (G_OBJECT (x
->handlebox_widget
), "child-detached",
3013 G_CALLBACK (xg_tool_bar_detach_callback
), f
);
3014 g_signal_connect (G_OBJECT (x
->handlebox_widget
), "child-attached",
3015 G_CALLBACK (xg_tool_bar_attach_callback
), f
);
3016 g_signal_connect (G_OBJECT (x
->toolbar_widget
),
3018 G_CALLBACK (xg_tool_bar_expose_callback
),
3021 gtk_widget_show_all (x
->handlebox_widget
);
3023 gtk_widget_size_request (x
->toolbar_widget
, &req
);
3024 FRAME_TOOLBAR_HEIGHT (f
) = req
.height
;
3026 /* The height has changed, resize outer widget and set columns
3027 rows to what we had before adding the tool bar. */
3028 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
3030 SET_FRAME_GARBAGED (f
);
3034 update_frame_tool_bar (f
)
3038 GtkRequisition old_req
, new_req
;
3041 struct x_output
*x
= f
->output_data
.x
;
3043 if (! FRAME_GTK_WIDGET (f
))
3048 if (! x
->toolbar_widget
)
3049 xg_create_tool_bar (f
);
3051 gtk_widget_size_request (x
->toolbar_widget
, &old_req
);
3053 icon_list
= gtk_container_get_children (GTK_CONTAINER (x
->toolbar_widget
));
3056 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
3058 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
3060 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
3061 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
3066 GtkWidget
*wicon
= iter
? GTK_WIDGET (iter
->data
) : 0;
3068 if (iter
) iter
= g_list_next (iter
);
3070 /* If image is a vector, choose the image according to the
3072 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
3073 if (VECTORP (image
))
3077 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
3078 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
3081 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
3082 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
3084 xassert (ASIZE (image
) >= idx
);
3085 image
= AREF (image
, idx
);
3090 /* Ignore invalid image specifications. */
3091 if (!valid_image_p (image
))
3093 if (wicon
) gtk_widget_hide (wicon
);
3097 img_id
= lookup_image (f
, image
);
3098 img
= IMAGE_FROM_ID (f
, img_id
);
3099 prepare_image_for_display (f
, img
);
3101 if (img
->load_failed_p
|| img
->pixmap
== None
)
3103 if (wicon
) gtk_widget_hide (wicon
);
3109 GdkPixmap
*gpix
= gdk_pixmap_foreign_new (img
->pixmap
);
3110 GdkBitmap
*gmask
= img
->mask
?
3111 (GdkBitmap
*) gdk_pixmap_foreign_new (img
->mask
) : 0;
3113 GtkWidget
*w
= gtk_image_new_from_pixmap (gpix
, gmask
);
3114 gtk_toolbar_append_item (GTK_TOOLBAR (x
->toolbar_widget
),
3117 GTK_SIGNAL_FUNC (xg_tool_bar_callback
),
3120 /* Save the image so we can see if an update is needed when
3121 this function is called again. */
3122 g_object_set_data (G_OBJECT (w
), XG_TOOL_BAR_IMAGE_DATA
,
3123 (gpointer
)img
->pixmap
);
3125 /* Catch expose events to overcome an annoying redraw bug, see
3126 comment for xg_tool_bar_item_expose_callback. */
3127 g_signal_connect (G_OBJECT (w
),
3129 G_CALLBACK (xg_tool_bar_item_expose_callback
),
3132 /* We must set sensitive on the button that is the parent
3133 of the GtkImage parent. Go upwards until we find the button. */
3134 while (! GTK_IS_BUTTON (w
))
3135 w
= gtk_widget_get_parent (w
);
3139 /* Save the frame in the button so the xg_tool_bar_callback
3141 g_object_set_data (G_OBJECT (w
), XG_FRAME_DATA
, (gpointer
)f
);
3142 gtk_widget_set_sensitive (w
, enabled_p
);
3144 /* Use enter/leave notify to show help. We use the events
3145 rather than the GtkButton specific signals "enter" and
3146 "leave", so we can have only one callback. The event
3147 will tell us what kind of event it is. */
3148 g_signal_connect (G_OBJECT (w
),
3149 "enter-notify-event",
3150 G_CALLBACK (xg_tool_bar_help_callback
),
3152 g_signal_connect (G_OBJECT (w
),
3153 "leave-notify-event",
3154 G_CALLBACK (xg_tool_bar_help_callback
),
3160 /* The child of the tool bar is a button. Inside that button
3161 is a vbox. Inside that vbox is the GtkImage. */
3162 GtkWidget
*wvbox
= gtk_bin_get_child (GTK_BIN (wicon
));
3163 GList
*chlist
= gtk_container_get_children (GTK_CONTAINER (wvbox
));
3164 GtkImage
*wimage
= GTK_IMAGE (chlist
->data
);
3165 Pixmap old_img
= (Pixmap
)g_object_get_data (G_OBJECT (wimage
),
3166 XG_TOOL_BAR_IMAGE_DATA
);
3167 g_list_free (chlist
);
3169 if (old_img
!= img
->pixmap
)
3171 GdkPixmap
*gpix
= gdk_pixmap_foreign_new (img
->pixmap
);
3172 GdkBitmap
*gmask
= img
->mask
?
3173 (GdkBitmap
*) gdk_pixmap_foreign_new (img
->mask
) : 0;
3175 gtk_image_set_from_pixmap (wimage
, gpix
, gmask
);
3178 g_object_set_data (G_OBJECT (wimage
), XG_TOOL_BAR_IMAGE_DATA
,
3179 (gpointer
)img
->pixmap
);
3181 gtk_widget_set_sensitive (wicon
, enabled_p
);
3182 gtk_widget_show (wicon
);
3188 /* Remove buttons not longer needed. We just hide them so they
3189 can be reused later on. */
3192 GtkWidget
*w
= GTK_WIDGET (iter
->data
);
3193 gtk_widget_hide (w
);
3194 iter
= g_list_next (iter
);
3197 gtk_widget_size_request (x
->toolbar_widget
, &new_req
);
3198 if (old_req
.height
!= new_req
.height
)
3200 FRAME_TOOLBAR_HEIGHT (f
) = new_req
.height
;
3201 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
3204 if (icon_list
) g_list_free (icon_list
);
3210 free_frame_tool_bar (f
)
3213 struct x_output
*x
= f
->output_data
.x
;
3215 if (x
->toolbar_widget
)
3218 gtk_container_remove (GTK_CONTAINER (x
->vbox_widget
),
3219 x
->handlebox_widget
);
3220 x
->toolbar_widget
= 0;
3221 x
->handlebox_widget
= 0;
3222 FRAME_TOOLBAR_HEIGHT (f
) = 0;
3224 /* The height has changed, resize outer widget and set columns
3225 rows to what we had before removing the tool bar. */
3226 xg_resize_outer_widget (f
, FRAME_COLS (f
), FRAME_LINES (f
));
3228 SET_FRAME_GARBAGED (f
);
3235 /***********************************************************************
3237 ***********************************************************************/
3241 xg_ignore_gtk_scrollbar
= 0;
3242 xg_left_ptr_cursor
= 0;
3245 xg_menu_cb_list
.prev
= xg_menu_cb_list
.next
=
3246 xg_menu_item_cb_list
.prev
= xg_menu_item_cb_list
.next
= 0;
3248 id_to_widget
.max_size
= id_to_widget
.used
= 0;
3249 id_to_widget
.widgets
= 0;
3251 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
3252 bindings. It doesn't seem to be any way to remove properties,
3253 so we set it to VoidSymbol which in X means "no key". */
3254 gtk_settings_set_string_property (gtk_settings_get_default (),
3255 "gtk-menu-bar-accel",
3259 /* Make GTK text input widgets use Emacs style keybindings. This is
3261 gtk_settings_set_string_property (gtk_settings_get_default (),
3262 "gtk-key-theme-name",
3267 #endif /* USE_GTK */