/* Support for embedding GTK (4) widgets in a frame Copyright (C) 2011-2020 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #define __GI_SCANNER__ #include "pgtkembed.h" #include "frame.h" #include "pgtkterm.h" #include "pgtksubr.h" #include "coding.h" #include "keyboard.h" #undef __GI_SCANNER__ static gboolean embedded_widget_click_cb (GtkButton *btn, gpointer user_data) { Lisp_Object arf = ((struct embedded_widget*) user_data)->callbacks; if (!NILP (arf)) for (; CONSP (arf); arf = XCDR (arf)) if (FUNCTIONP (XCAR (arf))) call0 (XCAR (arf)); return true; } #ifndef FIX_GTK_LEGACY_HANDLER_BUG static gboolean embedded_grab_cb (GtkEventControllerLegacy *controller, GdkEvent *event, gpointer user_data) { if (gdk_event_get_event_type (event) == GDK_BUTTON_PRESS) { struct frame *frame = user_data; gdouble x, y; gdk_event_get_position (event, &x, &y); GtkAllocation alloc; gtk_widget_get_allocation (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (controller)), &alloc); x += alloc.x; y += alloc.y; Lisp_Object window = window_from_coordinates (frame, (int) x, (int) y, 0, false, false); if (!NILP (window)) Fselect_window (window, Qnil); } return false; } #endif static gboolean embedded_key_cb (GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data) { static bool kmflag = 0; static bool zflag = 0; struct frame *f = user_data; int keystate = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state); guint c = keyval; if (c > 255 || keycode == GDK_KEY_Back) return false; gchar cc = (gchar) keyval; Lisp_Object keyl = list1 (intern_c_string_1 (&cc, 1)); if (keystate & ctrl_modifier) keyl = Fcons (Qcontrol, keyl); if (keystate & meta_modifier) keyl = Fcons (Qmeta, keyl); if (keystate & hyper_modifier) keyl = Fcons (Qhyper, keyl); if (keystate & super_modifier) keyl = Fcons (Qsuper, keyl); if (keystate & shift_modifier) keyl = Fcons (intern_c_string ("shift"), keyl); if (keystate & alt_modifier) keyl = Fcons (Qalt, keyl); Lisp_Object keymap = call1 (intern_c_string ("key-binding"), make_vector (1, keyl)); if (!NILP (call1 (Qkeymapp, keymap))) kmflag = 1; else if (kmflag && !this_command_key_count) { kmflag = 0; goto kfl; } if (kmflag) { kfl:; union buffered_input_event inev; EVENT_INIT (inev); inev.ie.kind = ASCII_KEYSTROKE_EVENT; inev.ie.arg = Qnil; inev.ie.code = XFIXNAT (make_fixnum ((int) c)); XSETFRAME (inev.ie.frame_or_window, f); inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state); inev.ie.timestamp = 0; evq_enqueue ((void *) &inev); if (!this_command_key_count) zflag = 1; else zflag = 0; if (!kmflag || zflag) { zflag = 0; kmflag = 0; pgtk_focus_frame (f, false); } } return kmflag; } static void embedded_entry_submit_cb (GtkEntry *entry, gpointer user_data) { Lisp_Object arf = ((struct embedded_widget*) user_data)->callbacks; if (Flistp (arf)) for (; CONSP (arf); arf = XCDR (arf)) if (FUNCTIONP (XCAR (arf))) call1 (XCAR (arf), build_string_from_utf8 (gtk_entry_buffer_get_text (gtk_entry_get_buffer (entry)))); } Lisp_Object create_embedded_widget (Lisp_Object type, Lisp_Object frame) { struct embedded_widget *widget = ALLOCATE_PSEUDOVECTOR (struct embedded_widget, callbacks, PVEC_EMBEDDED_WIDGET); EMBEDDED_WIDGET_PVEC_INIT (widget); if (EQ (type, intern_c_string ("label"))) { widget->actual_widget = GTK_WIDGET (gtk_label_new ("")); } else if (EQ (type, intern_c_string ("text"))) { GtkTextView *entry = GTK_TEXT_VIEW (gtk_text_view_new ()); widget->actual_widget = GTK_WIDGET (entry); } else if (EQ (type, intern_c_string ("scrolled-window"))) { GtkScrolledWindow *window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL)); widget->actual_widget = GTK_WIDGET (window); } else if (EQ (type, intern_c_string ("video"))) { GtkVideo *video = GTK_VIDEO (gtk_video_new ()); widget->actual_widget = GTK_WIDGET (video); } else if (EQ (type, intern_c_string ("button"))) { GtkButton *btn = GTK_BUTTON (gtk_button_new ()); widget->actual_widget = GTK_WIDGET (btn); g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (embedded_widget_click_cb), (gpointer) widget); } else if (EQ (type, intern_c_string ("vbox"))) { widget->actual_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); } else if (EQ (type, intern_c_string ("hbox"))) { widget->actual_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); } else if (EQ (type, intern_c_string ("entry"))) { widget->actual_widget = gtk_entry_new (); g_signal_connect (G_OBJECT (widget->actual_widget), "activate", G_CALLBACK (embedded_entry_submit_cb), (gpointer) widget); } else if (EQ (type, intern_c_string ("viewport"))) { widget->actual_widget = gtk_viewport_new (NULL, NULL); } else if (EQ (type, intern_c_string ("frame"))) { widget->actual_widget = gtk_frame_new (""); } else if (EQ (type, intern_c_string ("hseparator"))) { widget->actual_widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); } else if (EQ (type, intern_c_string ("vseparator"))) { widget->actual_widget = gtk_separator_new (GTK_ORIENTATION_VERTICAL); } else if (EQ (type, intern_c_string ("image"))) { widget->actual_widget = gtk_image_new (); } else if (EQ (type, intern_c_string ("header-bar"))) { widget->actual_widget = gtk_header_bar_new (); } else { widget->actual_widget = gtk_text_new (); error ("Widget not supported: %s", SSDATA (SYMBOL_NAME (type))); } g_object_ref (widget->actual_widget); widget->type = type; widget->frame = frame; widget->fx = make_fixnum (0); widget->fy = make_fixnum (0); widget->width = Qnil; widget->height = Qnil; widget->data_alist = Qnil; widget->callbacks = Qnil; widget->controller = gtk_event_controller_key_new (); widget->controller_2 = GTK_EVENT_CONTROLLER (gtk_event_controller_legacy_new ()); gtk_event_controller_set_propagation_phase (widget->controller, GTK_PHASE_CAPTURE); gtk_event_controller_set_propagation_phase (widget->controller_2, GTK_PHASE_CAPTURE); gtk_widget_add_controller (widget->actual_widget, widget->controller); gtk_widget_add_controller (widget->actual_widget, widget->controller_2); g_signal_connect (G_OBJECT (widget->controller), "key-pressed", G_CALLBACK (embedded_key_cb), XFRAME (widget->frame)); #ifndef FIX_GTK_LEGACY_HANDLER_BUG g_signal_connect (G_OBJECT (widget->controller_2), "event", G_CALLBACK (embedded_grab_cb), XFRAME (widget->frame)); #endif g_object_set_data (G_OBJECT (widget->actual_widget), "embedded-widget-p", (gpointer) true); g_object_ref (widget->controller); g_object_ref (widget->controller_2); Lisp_Object ret; XSETGTKWIDGET (ret, widget); return ret; } static void show_embedded_widget (struct frame *f, struct embedded_widget *widget) { GtkOverlay *outer_overlay = FRAME_DECOR_OVERLAY (f); gtk_overlay_add_overlay (outer_overlay, widget->actual_widget); } static void hide_embedded_widget (struct embedded_widget *widget) { g_object_ref (widget->actual_widget); gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (widget->actual_widget)), widget->actual_widget); g_object_unref (G_OBJECT (widget->actual_widget)); } static void set_widget_parent (struct embedded_widget *parent, struct embedded_widget *child) { if (parent->frame != child->frame) error ("Cannot set embedded widget parents across frames"); if (!GTK_IS_CONTAINER (parent->actual_widget)) error ("Parent type is not a container"); gtk_container_add (GTK_CONTAINER (parent->actual_widget), child->actual_widget); } static void update_widget_params (struct embedded_widget *widget) { GdkRectangle *rect = g_object_get_data (G_OBJECT (widget->actual_widget), EG_OVERLAY_ALLOC); if (!rect) { rect = g_malloc (sizeof *rect); g_object_set_data_full (G_OBJECT (widget->actual_widget), EG_OVERLAY_ALLOC, rect, g_free); } rect->x = XFIXNUM (widget->fx); rect->y = XFIXNUM (widget->fy); rect->height = !NILP (widget->height) ? XFIXNUM (widget->height) : -1; rect->width = !NILP (widget->width) ? XFIXNUM (widget->width) : -1; } DEFUN ("gtk-text-set-text-buffer-contents",Fgtk_text_set_text_buffer_contents, Sgtk_text_set_text_buffer_contents, 2, 2, 0, doc: /* Set the contents of WIDGET to TEXT. */) (Lisp_Object text, Lisp_Object widget) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); CHECK_STRING (text); if (!GTK_IS_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget)) error ("Not an entry"); GtkTextBuffer *buf = gtk_text_buffer_new (NULL); gtk_text_buffer_set_text (buf, SSDATA (ENCODE_UTF_8 (text)), XFIXNUM (Flength (text))); gtk_text_view_set_buffer (GTK_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget), buf); return text; } DEFUN ("gtk-image-set-filename", Fgtk_image_set_filename, Sgtk_image_set_filename, 2, 2, 0, doc: /* Show the file FILE in the image widget WIDGET. */) (Lisp_Object file, Lisp_Object widget) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); if (!GTK_IS_IMAGE (XGTKWIDGET (widget)->actual_widget)) error ("Not an image"); CHECK_STRING (file); gtk_image_set_from_file (GTK_IMAGE (XGTKWIDGET (widget)->actual_widget), SSDATA (ENCODE_UTF_8 (file))); return file; } DEFUN ("gtk-text-get-text-buffer-contents", Fgtk_text_get_text_buffer_contents, Sgtk_text_get_text_bufer_contents, 1, 1, 0, doc: /* Return the contents of the text widget WIDGET. */) (Lisp_Object widget) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); if (!GTK_IS_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget)) error ("Not an text"); GtkTextIter iter; GtkTextIter ter; gtk_text_buffer_get_start_iter (gtk_text_view_get_buffer (GTK_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget)), &iter); gtk_text_buffer_get_end_iter (gtk_text_view_get_buffer (GTK_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget)), &ter); return build_string_from_utf8 (gtk_text_buffer_get_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (XGTKWIDGET (widget)->actual_widget)), &iter, &ter, false)); } DEFUN ("set-gtk-widget-size", Fset_gtk_widget_size, Sset_gtk_widget_size, 5, 5, 0, doc: /* Set the size of WIDGET to X, Y by WIDTH, HEIGHT. */) (Lisp_Object widget, Lisp_Object x, Lisp_Object y, Lisp_Object width, Lisp_Object height) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); if (!NILP (x)) CHECK_FIXNUM (x); if (!NILP (y)) CHECK_FIXNUM (y); if (!NILP (width)) CHECK_FIXNUM (width); if (!NILP (height)) CHECK_FIXNUM (height); struct embedded_widget *ewidget = XGTKWIDGET (widget); ewidget->fx = x; ewidget->fy = y; ewidget->width = width; ewidget->height = height; update_widget_params (ewidget); gtk_widget_queue_allocate (ewidget->actual_widget); if (gtk_widget_get_parent (ewidget->actual_widget)) gtk_widget_queue_resize (gtk_widget_get_parent (ewidget->actual_widget)); return Qnil; } DEFUN ("set-gtk-widget-parent", Fset_gtk_widget_parent, Sset_gtk_widget_parent, 2, 2, 0, doc: /* Set WIDGET's parent to PARENT. */) (Lisp_Object parent, Lisp_Object widget) { CHECK_GTKWIDGET (parent); CHECK_GTKWIDGET (widget); set_widget_parent (XGTKWIDGET (parent), XGTKWIDGET (widget)); return Qnil; } DEFUN ("show-gtk-widget", Fshow_gtk_widget, Sshow_gtk_widget, 1, 1, 0, doc: /* Display WIDGET in WIDGET's frame. */) (Lisp_Object widget) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); update_widget_params (XGTKWIDGET (widget)); show_embedded_widget (XFRAME (XGTKWIDGET (widget)->frame), XGTKWIDGET (widget)); return Qnil; } DEFUN ("hide-gtk-widget", Fhide_gtk_widget, Shide_gtk_widget, 1, 1, 0, doc: /* Remove the widget WIDGET from it's frame. */) (Lisp_Object widget) { update_widget_params (XGTKWIDGET (widget)); hide_embedded_widget (XGTKWIDGET (widget)); return Qnil; } DEFUN ("make-gtk-widget", Fmake_gtk_widget, Smake_gtk_widget, 2, 2, 0, doc: /* Create a GTK widget with the type TYPE, bound to the frame FRAME. TYPE can be one of the following: - label (A GtkLabel). - vbox (A vertical GtkBox). - text (A GtkTextView) - video (A GtkVideo) - button (A GtkButton) - hbox (A horizontal GtkBox) - entry (A GtkEntry) */) (Lisp_Object type, Lisp_Object frame) { CHECK_LIVE_FRAME (frame); return create_embedded_widget (type, frame); } DEFUN ("gtk-video-set-filename", Fgtk_video_set_filename, Sgtk_video_set_filename, 2, 2, 0, doc: /* Open the file FILE in the media player widget WIDGET. */) (Lisp_Object file, Lisp_Object widget) { CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); if (!GTK_IS_VIDEO (XGTKWIDGET (widget)->actual_widget)) error ("Not a video widget"); CHECK_STRING (file); gtk_video_set_filename (GTK_VIDEO (XGTKWIDGET (widget)->actual_widget), SSDATA (ENCODE_UTF_8 (file))); return file; } DEFUN ("gtk-label-set-text", Fgtk_label_set_text, Sgtk_label_set_text, 2, 3, 0, doc: /* Set the contents of LABEL to the string TEXT, using markup if MARKUP is non-nil. */) (Lisp_Object text, Lisp_Object label, Lisp_Object markup) { CHECK_GTKWIDGET (label); CHECK_LIVE_FRAME (XGTKWIDGET (label)->frame); if (!GTK_IS_LABEL (XGTKWIDGET (label)->actual_widget)) error ("Not a label widegt"); CHECK_STRING (text); if (NILP (markup)) gtk_label_set_text (GTK_LABEL (XGTKWIDGET (label)->actual_widget), SSDATA (ENCODE_UTF_8 (text))); else gtk_label_set_markup (GTK_LABEL (XGTKWIDGET (label)->actual_widget), SSDATA (ENCODE_UTF_8 (text))); return text; } DEFUN ("gtk-entry-set-text", Fgtk_entry_set_text, Sgtk_entry_set_text, 2, 2, 0, doc: /* Set the contents of LABEL to the string TEXT */) (Lisp_Object text, Lisp_Object entry) { CHECK_GTKWIDGET (entry); CHECK_LIVE_FRAME (XGTKWIDGET (entry)->frame); if (!GTK_IS_ENTRY (XGTKWIDGET (entry)->actual_widget)) error ("Not an widegt"); CHECK_STRING (text); gtk_entry_buffer_set_text (gtk_entry_get_buffer (GTK_ENTRY (XGTKWIDGET (entry)->actual_widget)), SSDATA (ENCODE_UTF_8 (text)), -1); return text; } DEFUN ("gtk-entry-get-text", Fgtk_entry_get_text, Sgtk_entry_get_text, 1, 1, 0, doc: /* Get the contents of the entry ENTRY; */) (Lisp_Object entry) { CHECK_GTKWIDGET (entry); CHECK_LIVE_FRAME (XGTKWIDGET (entry)->frame); if (!GTK_IS_ENTRY (XGTKWIDGET (entry)->actual_widget)) error ("Not an widegt"); return build_string_from_utf8 (gtk_entry_buffer_get_text (gtk_entry_get_buffer (GTK_ENTRY (XGTKWIDGET (entry)->actual_widget)))); } DEFUN ("gtk-widget-put-callback", Fgtk_widget_put_callback, Sgtk_widget_put_callback, 2, 2, 0, doc: /* Attatch CALLBACK to WIDGET */) (Lisp_Object callback, Lisp_Object widget) { if (!FUNCTIONP (callback)) wrong_type_argument (intern_c_string ("functionp"), widget); CHECK_GTKWIDGET (widget); CHECK_LIVE_FRAME (XGTKWIDGET (widget)->frame); XGTKWIDGET (widget)->callbacks = Fcons (callback, XGTKWIDGET (widget)->callbacks); return XGTKWIDGET (widget)->callbacks; } DEFUN ("gtk-button-set-text", Fgtk_button_set_text, Sgtk_button_set_text, 2, 2, 0, doc: /* Set BUTTON's text to TEXT. */) (Lisp_Object text, Lisp_Object button) { CHECK_GTKWIDGET (button); CHECK_LIVE_FRAME (XGTKWIDGET (button)->frame); CHECK_STRING (text); if (!GTK_IS_BUTTON (XGTKWIDGET (button)->actual_widget)) error ("Not a button widget"); gtk_button_set_label (GTK_BUTTON (XGTKWIDGET (button)->actual_widget), SSDATA (ENCODE_UTF_8 (text))); return text; } DEFUN ("gtk-button-set-icon", Fgtk_button_set_icon, Sgtk_button_set_icon, 2, 2, 0, doc: /* Set BUTTON's icon name to ICON. */) (Lisp_Object icon, Lisp_Object button) { CHECK_GTKWIDGET (button); CHECK_LIVE_FRAME (XGTKWIDGET (button)->frame); CHECK_STRING (icon); if (!GTK_IS_BUTTON (XGTKWIDGET (button)->actual_widget)) error ("Not a button widget"); gtk_button_set_icon_name (GTK_BUTTON (XGTKWIDGET (button)->actual_widget), SSDATA (ENCODE_UTF_8 (icon))); return button; } DEFUN ("gtk-entry-set-hint", Fgtk_entry_set_hint, Sgtk_entry_set_hint, 2, 2, 0, doc: /* Set ENTRY's hint to HINT. */ attributes: const) (Lisp_Object hint, Lisp_Object entry) { CHECK_STRING (hint); CHECK_GTKWIDGET (entry); CHECK_LIVE_FRAME (XGTKWIDGET (entry)->frame); if (!GTK_IS_ENTRY (XGTKWIDGET (entry)->actual_widget)) error ("Not an entry"); gtk_entry_set_placeholder_text (GTK_ENTRY (XGTKWIDGET (entry)->actual_widget), SSDATA (ENCODE_UTF_8 (hint))); return hint; } DEFUN ("gtk-box-set-item-margin", Fgtk_box_set_item_margin, Sgtk_box_set_item_margin, 2, 2, 0, doc: /* Set the space between BOX's items to SPACE. */) (Lisp_Object space, Lisp_Object box) { CHECK_FIXNUM (space); CHECK_GTKWIDGET (box); struct embedded_widget *widget = XGTKWIDGET (box); CHECK_LIVE_FRAME (widget->frame); if (!GTK_IS_BOX (widget->actual_widget)) error ("Not a box"); gtk_box_set_spacing (GTK_BOX (widget->actual_widget), XFIXNUM (space)); return space; } DEFUN ("gtk-text-set-monospace", Fgtk_text_set_monospace, Sgtk_text_set_monospace, 2, 2, 0, doc: /* TEXT's text will be displayed in monospace if MONO is non-nil. */) (Lisp_Object mono, Lisp_Object label) { CHECK_GTKWIDGET (label); struct embedded_widget *widget = XGTKWIDGET (label); CHECK_LIVE_FRAME (widget->frame); if (!GTK_IS_TEXT_VIEW (widget->actual_widget)) error ("Not a text"); gtk_text_view_set_monospace (GTK_TEXT_VIEW (widget->actual_widget), true); return mono; } DEFUN ("gtk-frame-set-label", Fgtk_frame_set_label, Sgtk_frame_set_label, 2, 2, 0, doc: /* Set FRAME's label to LABEL. */) (Lisp_Object label, Lisp_Object frame) { CHECK_STRING (label); CHECK_GTKWIDGET (frame); struct embedded_widget *widget = XGTKWIDGET (frame); if (!GTK_IS_FRAME (widget->actual_widget)) error ("Not a frame"); gtk_frame_set_label (GTK_FRAME (widget->actual_widget), SSDATA (ENCODE_UTF_8 (label))); return label; } DEFUN ("gtkwidgetp", Fgtkwidgetp, Sgtkwidgetp, 1, 1, 0, doc: /* Returns t if IT is a GTK widget, else nil. */) (Lisp_Object it) { return GTKWIDGETP (it) ? Qt : Qnil; } DEFUN ("gtk-widget-type", Fgtk_widget_type, Sgtk_widget_type, 1, 1, 0, doc: /* Return the GObject type name of the widget WIDGET. */) (Lisp_Object widget) { CHECK_GTKWIDGET (widget); return intern_c_string (G_OBJECT_TYPE_NAME (G_OBJECT (XGTKWIDGET (widget)->actual_widget))); } DEFUN ("gtk-header-bar-set-title", Fgtk_header_bar_set_title, Sgtk_header_bar_set_title, 2, 2, 0, doc: /* Set HEADER-BAR's title to TITLE. */) (Lisp_Object title, Lisp_Object header_bar) { CHECK_GTKWIDGET (header_bar); CHECK_STRING (title); if (!GTK_IS_HEADER_BAR (XGTKWIDGET (header_bar)->actual_widget)) error ("Not a header-bar widget"); gtk_header_bar_set_title (GTK_HEADER_BAR (XGTKWIDGET (header_bar)->actual_widget), SSDATA (ENCODE_UTF_8 (title))); return title; } void syms_of_pgtkembed (void) { DEFSYM (Qgtkwidgetp, "gtkwidgetp"); DEFSYM (Qembedded_widgets, "embedded-widgets"); defsubr (&Sgtkwidgetp); defsubr (&Smake_gtk_widget); defsubr (&Sshow_gtk_widget); defsubr (&Shide_gtk_widget); defsubr (&Sset_gtk_widget_size); defsubr (&Sset_gtk_widget_parent); defsubr (&Sgtk_video_set_filename); defsubr (&Sgtk_text_get_text_bufer_contents); defsubr (&Sgtk_text_set_text_buffer_contents); defsubr (&Sgtk_label_set_text); defsubr (&Sgtk_widget_put_callback); defsubr (&Sgtk_button_set_text); defsubr (&Sgtk_entry_set_text); defsubr (&Sgtk_entry_set_hint); defsubr (&Sgtk_box_set_item_margin); defsubr (&Sgtk_button_set_icon); defsubr (&Sgtk_text_set_monospace); defsubr (&Sgtk_entry_get_text); defsubr (&Sgtk_frame_set_label); defsubr (&Sgtk_widget_type); defsubr (&Sgtk_header_bar_set_title); defsubr (&Sgtk_image_set_filename); Fprovide (Qembedded_widgets, Qnil); }