diff options
author | Po Lu <luangruo@yahoo.com> | 2022-06-23 13:38:30 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-06-23 13:58:38 +0800 |
commit | 0b4db66a9deae682dc7d444f4ab8d0e49f15c3b9 (patch) | |
tree | 6f08101c3b9697085153e3babe29dc379d031b9c /src/pgtkterm.c | |
parent | 00034ad2e635adc93cd1d6dcb1b500c10d990c74 (diff) | |
download | emacs-0b4db66a9deae682dc7d444f4ab8d0e49f15c3b9.tar.gz |
Allow dropping more data types on PGTK
* lisp/loadup.el (featurep): Load `pgtk-dnd'.
* lisp/pgtk-dnd.el: New file.
(pgtk-dnd-test-function, pgtk-dnd-types-alist)
(pgtk-dnd-known-types, pgtk-dnd-use-offix-drop)
(pgtk-dnd-current-state, pgtk-get-selection-internal)
(pgtk-register-dnd-targets, pgtk-dnd-empty-state)
(pgtk-dnd-init-frame, pgtk-dnd-get-state-cons-for-frame)
(pgtk-dnd-get-state-for-frame, pgtk-dnd-default-test-function)
(pgtk-dnd-current-type, pgtk-dnd-forget-drop)
(pgtk-dnd-maybe-call-test-function, pgtk-dnd-save-state)
(pgtk-dnd-handle-moz-url, pgtk-dnd-insert-utf8-text)
(pgtk-dnd-insert-utf16-text, pgtk-dnd-insert-ctext)
(pgtk-dnd-handle-uri-list, pgtk-dnd-handle-file-name)
(pgtk-dnd-choose-type, pgtk-dnd-drop-data)
(pgtk-dnd-handle-drag-n-drop-event, pgtk-update-drop-status)
(pgtk-drop-finish, pgtk-dnd-handle-gdk, pgtk-dnd): New variables
and functions and library.
* lisp/term/pgtk-win.el (special-event-map): Load
`drag-n-drop-event'.
(after-make-frame-functions): Register DND after make frame
functions.
* src/emacs.c (main): Stop calling empty init_pgtkterm function.
* src/pgtkselect.c (Fpgtk_register_dnd_targets, Fpgtk_drop_finish)
(Fpgtk_update_drop_status): New functions.
(syms_of_pgtkselect): Register new functions.
* src/pgtkterm.c (struct event_queue_t): Fix coding style of
definition.
(symbol_to_drag_action, drag_action_to_symbol)
(pgtk_update_drop_status, pgtk_finish_drop): New functions.
(drag_data_received): Delete function.
(pgtk_set_event_handler): Register for DND correctly.
(syms_of_pgtkterm): New defsyms for DND types.
(init_pgtkterm): Delete function.
* src/pgtkterm.h: Update prototypes, fix prototype coding style.
Diffstat (limited to 'src/pgtkterm.c')
-rw-r--r-- | src/pgtkterm.c | 276 |
1 files changed, 234 insertions, 42 deletions
diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 91874ff58a5..a123311366a 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -76,25 +76,36 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ static bool any_help_event_p; -struct pgtk_display_info *x_display_list; /* Chain of existing displays */ -extern Lisp_Object tip_frame; +/* Chain of existing displays */ +struct pgtk_display_info *x_display_list; -static struct event_queue_t +struct event_queue_t { union buffered_input_event *q; int nr, cap; -} event_q = { - NULL, 0, 0, }; +/* A queue of events that will be read by the read_socket_hook. */ +static struct event_queue_t event_q; + /* Non-zero timeout value means ignore next mouse click if it arrives before that timeout elapses (i.e. as part of the same sequence of events resulting from clicking on a frame to select it). */ - static Time ignore_next_mouse_click_timeout; +/* The default Emacs icon . */ static Lisp_Object xg_default_icon_file; +/* The current GdkDragContext of a drop. */ +static GdkDragContext *current_drop_context; + +/* Whether or not current_drop_context was set from a drop + handler. */ +static bool current_drop_context_drop; + +/* The time of the last drop. */ +static guint32 current_drop_time; + static void pgtk_delete_display (struct pgtk_display_info *); static void pgtk_clear_frame_area (struct frame *, int, int, int, int); static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int, @@ -6146,40 +6157,217 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) return TRUE; } + + +/* C part of drop handling code. + The Lisp part is in pgtk-dnd.el. */ + +static GdkDragAction +symbol_to_drag_action (Lisp_Object act) +{ + if (EQ (act, Qcopy)) + return GDK_ACTION_COPY; + + if (EQ (act, Qmove)) + return GDK_ACTION_MOVE; + + if (EQ (act, Qlink)) + return GDK_ACTION_LINK; + + if (EQ (act, Qprivate)) + return GDK_ACTION_PRIVATE; + + if (NILP (act)) + return GDK_ACTION_DEFAULT; + + signal_error ("Invalid drag acction", act); +} + +static Lisp_Object +drag_action_to_symbol (GdkDragAction action) +{ + switch (action) + { + case GDK_ACTION_COPY: + return Qcopy; + + case GDK_ACTION_MOVE: + return Qmove; + + case GDK_ACTION_LINK: + return Qlink; + + case GDK_ACTION_PRIVATE: + return Qprivate; + + case GDK_ACTION_DEFAULT: + default: + return Qnil; + } +} + +void +pgtk_update_drop_status (Lisp_Object action, Lisp_Object event_time) +{ + guint32 time; + + CONS_TO_INTEGER (event_time, guint32, time); + + if (!current_drop_context || time < current_drop_time) + return; + + gdk_drag_status (current_drop_context, + symbol_to_drag_action (action), + time); +} + +void +pgtk_finish_drop (Lisp_Object success, Lisp_Object event_time, + Lisp_Object del) +{ + guint32 time; + + CONS_TO_INTEGER (event_time, guint32, time); + + if (!current_drop_context || time < current_drop_time) + return; + + gtk_drag_finish (current_drop_context, !NILP (success), + !NILP (del), time); + + if (current_drop_context_drop) + g_clear_pointer (¤t_drop_context, + g_object_unref); +} + static void -drag_data_received (GtkWidget *widget, GdkDragContext *context, - gint x, gint y, GtkSelectionData *data, - guint info, guint time, gpointer user_data) +drag_leave (GtkWidget *widget, GdkDragContext *context, + guint time, gpointer user_data) { - struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - gchar **uris = gtk_selection_data_get_uris (data); + struct frame *f; + union buffered_input_event inev; + + f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - if (uris != NULL) + if (current_drop_context) { - for (int i = 0; uris[i] != NULL; i++) - { - union buffered_input_event inev; - Lisp_Object arg = Qnil; + if (current_drop_context_drop) + gtk_drag_finish (current_drop_context, + FALSE, FALSE, current_drop_time); - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + g_clear_pointer (¤t_drop_context, + g_object_unref); + } - arg = list2 (Qurl, build_string (uris[i])); + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = Qnil; + inev.ie.timestamp = time; - inev.ie.kind = DRAG_N_DROP_EVENT; - inev.ie.modifiers = 0; - XSETINT (inev.ie.x, x); - XSETINT (inev.ie.y, y); - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.arg = arg; - inev.ie.timestamp = 0; + XSETINT (inev.ie.x, 0); + XSETINT (inev.ie.y, 0); + XSETFRAME (inev.ie.frame_or_window, f); - evq_enqueue (&inev); - } + evq_enqueue (&inev); +} + +static gboolean +drag_motion (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time) + +{ + struct frame *f; + union buffered_input_event inev; + GdkAtom name; + GdkDragAction suggestion; + + f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); + + if (!f) + return FALSE; + + if (current_drop_context) + { + if (current_drop_context_drop) + gtk_drag_finish (current_drop_context, + FALSE, FALSE, current_drop_time); + + g_clear_pointer (¤t_drop_context, + g_object_unref); } - gtk_drag_finish (context, TRUE, FALSE, time); + current_drop_context = g_object_ref (context); + current_drop_time = time; + current_drop_context_drop = false; + + name = gdk_drag_get_selection (context); + suggestion = gdk_drag_context_get_suggested_action (context); + + EVENT_INIT (inev.ie); + + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (suggestion)); + inev.ie.timestamp = time; + + XSETINT (inev.ie.x, x); + XSETINT (inev.ie.y, y); + XSETFRAME (inev.ie.frame_or_window, f); + + evq_enqueue (&inev); + + return TRUE; +} + +static gboolean +drag_drop (GtkWidget *widget, GdkDragContext *context, + int x, int y, guint time, gpointer user_data) +{ + struct frame *f; + union buffered_input_event inev; + GdkAtom name; + GdkDragAction selected_action; + + f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); + + if (!f) + return FALSE; + + if (current_drop_context) + { + if (current_drop_context_drop) + gtk_drag_finish (current_drop_context, + FALSE, FALSE, current_drop_time); + + g_clear_pointer (¤t_drop_context, + g_object_unref); + } + + current_drop_context = g_object_ref (context); + current_drop_time = time; + current_drop_context_drop = true; + + name = gdk_drag_get_selection (context); + selected_action = gdk_drag_context_get_selected_action (context); + + EVENT_INIT (inev.ie); + + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (selected_action)); + inev.ie.timestamp = time; + + XSETINT (inev.ie.x, x); + XSETINT (inev.ie.y, y); + XSETFRAME (inev.ie.frame_or_window, f); + + evq_enqueue (&inev); + + return TRUE; } static void @@ -6208,9 +6396,9 @@ pgtk_set_event_handler (struct frame *f) return; } - gtk_drag_dest_set (FRAME_GTK_WIDGET (f), GTK_DEST_DEFAULT_ALL, NULL, 0, - GDK_ACTION_COPY); - gtk_drag_dest_add_uri_targets (FRAME_GTK_WIDGET (f)); + gtk_drag_dest_set (FRAME_GTK_WIDGET (f), 0, NULL, 0, + (GDK_ACTION_MOVE | GDK_ACTION_COPY + | GDK_ACTION_LINK | GDK_ACTION_PRIVATE)); if (FRAME_GTK_OUTER_WIDGET (f)) { @@ -6251,8 +6439,12 @@ pgtk_set_event_handler (struct frame *f) G_CALLBACK (scroll_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "configure-event", G_CALLBACK (configure_event), NULL); - g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-data-received", - G_CALLBACK (drag_data_received), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-leave", + G_CALLBACK (drag_leave), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-motion", + G_CALLBACK (drag_motion), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-drop", + G_CALLBACK (drag_drop), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw", G_CALLBACK (pgtk_handle_draw), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "property-notify-event", @@ -6803,12 +6995,17 @@ syms_of_pgtkterm (void) DEFSYM (Qlatin_1, "latin-1"); - xg_default_icon_file = - build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg"); + xg_default_icon_file + = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg"); staticpro (&xg_default_icon_file); DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock"); + DEFSYM (Qcopy, "copy"); + DEFSYM (Qmove, "move"); + DEFSYM (Qlink, "link"); + DEFSYM (Qprivate, "private"); + Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier)); Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier)); @@ -7093,8 +7290,3 @@ pgtk_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) return CALLN (Fapply, intern ("concat"), Fnreverse (acc)); } - -void -init_pgtkterm (void) -{ -} |