Mercurial > hg > xemacs-beta
annotate src/event-gtk.c @ 5464:e79916901603 r21-5-30
XEmacs 21.5.30 "garlic" is released.
author | Stephen J. Turnbull <stephen@xemacs.org> |
---|---|
date | Wed, 27 Apr 2011 01:24:28 +0900 |
parents | 71ee43b8a74d |
children | 308d34e9f07d |
rev | line source |
---|---|
462 | 1 /* The event_stream interface for X11 with gtk, and/or tty frames. |
2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
5139
a48ef26d87ee
Clean up prototypes for Lisp variables/symbols. Put decls for them with
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
4 Copyright (C) 1996, 2001, 2002, 2003, 2010 Ben Wing. |
462 | 5 Copyright (C) 2000 William Perry. |
6 | |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* This file is heavily based upon event-Xt.c */ | |
25 | |
26 /* Synched up with: Not in FSF. */ | |
27 | |
28 #include <config.h> | |
29 #include "lisp.h" | |
30 | |
31 #include "blocktype.h" | |
32 #include "buffer.h" | |
33 #include "commands.h" | |
34 #include "console.h" | |
872 | 35 #include "device-impl.h" |
36 #include "elhash.h" | |
462 | 37 #include "events.h" |
872 | 38 #include "file-coding.h" |
39 #include "frame-impl.h" | |
40 #include "lstream.h" | |
462 | 41 #include "process.h" |
42 #include "redisplay.h" | |
809 | 43 #include "window.h" |
872 | 44 |
45 #include "console-tty.h" | |
46 | |
47 #include "console-gtk-impl.h" | |
5176
8b2f75cecb89
rename objects* (.c, .h and .el files) to fontcolor*
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
48 #include "fontcolor-gtk.h" |
462 | 49 |
50 #include "gtk-xemacs.h" | |
51 | |
4908
b3ce27ca7647
various fixes related to gtk, redisplay-xlike-inc.c
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
52 #include "sysgdkx.h" |
b3ce27ca7647
various fixes related to gtk, redisplay-xlike-inc.c
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
53 |
462 | 54 #include "systime.h" |
55 #include "sysproc.h" /* for MAXDESC */ | |
56 | |
57 #ifdef HAVE_DRAGNDROP | |
58 #include "dragdrop.h" | |
59 #endif | |
60 | |
2081 | 61 #ifdef HAVE_MENUBARS |
62 # include "menubar.h" | |
63 #endif | |
64 | |
462 | 65 static struct event_stream *gtk_event_stream; |
66 | |
1292 | 67 #ifdef WIN32_ANY |
68 extern int mswindows_is_blocking; | |
69 #endif | |
70 | |
462 | 71 /* Do we accept events sent by other clients? */ |
72 int gtk_allow_sendevents; | |
73 | |
74 static int process_events_occurred; | |
75 static int tty_events_occurred; | |
76 | |
77 /* Mask of bits indicating the descriptors that we wait for input on */ | |
1415 | 78 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
79 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
462 | 80 |
2054 | 81 static Lisp_Object gtk_keysym_to_emacs_keysym (guint keysym, int simple_p); |
462 | 82 void debug_process_finalization (struct Lisp_Process *p); |
83 gboolean emacs_gtk_event_handler (GtkWidget *wid /* unused */, | |
84 GdkEvent *event, | |
85 gpointer closure /* unused */); | |
86 | |
87 static int last_quit_check_signal_tick_count; | |
88 | |
2489 | 89 /* |
90 * Identify if the keysym is a modifier. This implementation mirrors x.org's | |
91 * IsModifierKey(), but for GDK keysyms. | |
92 */ | |
93 #ifdef GDK_ISO_Lock | |
94 #define IS_MODIFIER_KEY(keysym) \ | |
95 ((((keysym) >= GDK_Shift_L) && ((keysym) <= GDK_Hyper_R)) \ | |
96 || (((keysym) >= GDK_ISO_Lock) && \ | |
97 ((keysym) <= GDK_ISO_Last_Group_Lock)) \ | |
98 || ((keysym) == GDK_Mode_switch) \ | |
99 || ((keysym) == GDK_Num_Lock)) | |
100 #else | |
462 | 101 #define IS_MODIFIER_KEY(keysym) \ |
102 ((((keysym) >= GDK_Shift_L) && ((keysym) <= GDK_Hyper_R)) \ | |
103 || ((keysym) == GDK_Mode_switch) \ | |
104 || ((keysym) == GDK_Num_Lock)) | |
2489 | 105 #endif |
462 | 106 |
1268 | 107 #define THIS_IS_GTK |
108 #include "event-xlike-inc.c" | |
462 | 109 |
110 | |
111 /************************************************************************/ | |
112 /* magic-event handling */ | |
113 /************************************************************************/ | |
114 static void | |
115 handle_focus_event_1 (struct frame *f, int in_p) | |
116 { | |
117 /* We don't want to handle the focus change now, because we might | |
118 be in an accept-process-output, sleep-for, or sit-for. So | |
119 we enqueue it. | |
120 | |
121 Actually, we half handle it: we handle it as far as changing the | |
122 box cursor for redisplay, but we don't call any hooks or do any | |
123 select-frame stuff until after the sit-for. | |
124 */ | |
125 | |
126 if (in_p) | |
127 { | |
128 GTK_WIDGET_SET_FLAGS (FRAME_GTK_TEXT_WIDGET (f), GTK_HAS_FOCUS); | |
129 } | |
130 else | |
131 { | |
132 GTK_WIDGET_UNSET_FLAGS (FRAME_GTK_TEXT_WIDGET (f), GTK_HAS_FOCUS); | |
133 } | |
134 gtk_widget_grab_focus (FRAME_GTK_TEXT_WIDGET (f)); | |
135 gtk_widget_draw_focus (FRAME_GTK_TEXT_WIDGET (f)); | |
136 | |
137 { | |
138 Lisp_Object frm; | |
139 Lisp_Object conser; | |
140 struct gcpro gcpro1; | |
141 | |
793 | 142 frm = wrap_frame (f); |
462 | 143 conser = Fcons (frm, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
144 GCPRO1 (conser); | |
145 | |
146 emacs_handle_focus_change_preliminary (conser); | |
147 enqueue_magic_eval_event (emacs_handle_focus_change_final, | |
148 conser); | |
149 UNGCPRO; | |
150 } | |
151 } | |
152 | |
153 /* both GDK_MAP and GDK_VISIBILITY_NOTIFY can cause this | |
154 JV is_visible has the same semantics as f->visible*/ | |
155 static void | |
156 change_frame_visibility (struct frame *f, int is_visible) | |
157 { | |
793 | 158 Lisp_Object frame = wrap_frame (f); |
462 | 159 |
160 | |
161 if (!FRAME_VISIBLE_P (f) && is_visible) | |
162 { | |
163 FRAME_VISIBLE_P (f) = is_visible; | |
872 | 164 /* [[ This improves the double flicker when uniconifying a frame |
462 | 165 some. A lot of it is not showing a buffer which has changed |
166 while the frame was iconified. To fix it further requires | |
872 | 167 the good 'ol double redisplay structure. ]] -- comment is |
168 invalid, obviously predates 19.12, when the double redisplay | |
169 structure (i.e. current + desired) was put back in. --ben */ | |
462 | 170 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); |
171 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
172 } | |
173 else if (FRAME_VISIBLE_P (f) && !is_visible) | |
174 { | |
175 FRAME_VISIBLE_P (f) = 0; | |
176 va_run_hook_with_args (Qunmap_frame_hook, 1, frame); | |
177 } | |
178 else if (FRAME_VISIBLE_P (f) * is_visible < 0) | |
179 { | |
180 FRAME_VISIBLE_P(f) = - FRAME_VISIBLE_P(f); | |
181 if (FRAME_REPAINT_P (f)) | |
182 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
183 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
184 } | |
185 } | |
186 | |
187 static void | |
188 handle_map_event (struct frame *f, GdkEvent *event) | |
189 { | |
793 | 190 Lisp_Object frame = wrap_frame (f); |
462 | 191 |
192 if (event->any.type == GDK_MAP) | |
193 { | |
194 FRAME_GTK_TOTALLY_VISIBLE_P (f) = 1; | |
195 change_frame_visibility (f, 1); | |
196 } | |
197 else | |
198 { | |
199 FRAME_GTK_TOTALLY_VISIBLE_P (f) = 0; | |
200 change_frame_visibility (f, 0); | |
201 /* Calling Fframe_iconified_p is the only way we have to | |
202 correctly update FRAME_ICONIFIED_P */ | |
203 Fframe_iconified_p (frame); | |
204 } | |
205 } | |
206 | |
207 static void | |
208 handle_client_message (struct frame *f, GdkEvent *event) | |
209 { | |
210 /* The event-Xt code used to handle WM_DELETE_WINDOW here, but we | |
211 handle that directly in frame-gtk.c */ | |
212 | |
213 if (event->client.message_type == gdk_atom_intern ("WM_PROTOCOLS", 0) && | |
214 (GdkAtom) event->client.data.l[0] == gdk_atom_intern ("WM_TAKE_FOCUS", 0)) | |
215 { | |
216 handle_focus_event_1 (f, 1); | |
217 } | |
218 } | |
219 | |
220 static void | |
788 | 221 emacs_gtk_format_magic_event (Lisp_Event *emacs_event, Lisp_Object pstream) |
222 { | |
789 | 223 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (emacs_event)); |
788 | 224 if (CONSOLE_GTK_P (XCONSOLE (console))) |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
225 write_cistring |
826 | 226 (pstream, |
1204 | 227 gtk_event_name (EVENT_MAGIC_GDK_EVENT (emacs_event).type)); |
788 | 228 } |
229 | |
230 static int | |
231 emacs_gtk_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
232 { | |
233 if (CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) && | |
234 CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
1204 | 235 return (!memcmp (&EVENT_MAGIC_GDK_EVENT (e1), |
236 &EVENT_MAGIC_GDK_EVENT (e2), | |
788 | 237 sizeof (GdkEvent))); |
238 if (CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) || | |
239 CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
240 return 0; | |
241 return 1; | |
242 } | |
243 | |
244 static Hashcode | |
245 emacs_gtk_hash_magic_event (Lisp_Event *e) | |
246 { | |
247 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (e)); | |
248 if (CONSOLE_GTK_P (XCONSOLE (console))) | |
1204 | 249 return memory_hash (&EVENT_MAGIC_GDK_EVENT (e), |
788 | 250 sizeof (GdkEvent)); |
251 return 0; | |
252 } | |
253 | |
254 static void | |
462 | 255 emacs_gtk_handle_magic_event (struct Lisp_Event *emacs_event) |
256 { | |
257 /* This function can GC */ | |
1204 | 258 GdkEvent *event = &EVENT_MAGIC_GDK_EVENT (emacs_event); |
462 | 259 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); |
260 | |
261 if (!FRAME_LIVE_P (f)) | |
262 return; | |
263 | |
264 switch (event->any.type) | |
265 { | |
266 case GDK_CLIENT_EVENT: | |
267 handle_client_message (f, event); | |
268 break; | |
269 | |
270 case GDK_FOCUS_CHANGE: | |
271 handle_focus_event_1 (f, event->focus_change.in); | |
272 break; | |
273 | |
274 case GDK_MAP: | |
275 case GDK_UNMAP: | |
276 handle_map_event (f, event); | |
277 break; | |
278 | |
279 case GDK_ENTER_NOTIFY: | |
280 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) | |
281 { | |
793 | 282 Lisp_Object frame = wrap_frame (f); |
462 | 283 |
284 /* FRAME_X_MOUSE_P (f) = 1; */ | |
285 va_run_hook_with_args (Qmouse_enter_frame_hook, 1, frame); | |
286 } | |
287 break; | |
288 | |
289 case GDK_LEAVE_NOTIFY: | |
290 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) | |
291 { | |
793 | 292 Lisp_Object frame = wrap_frame (f); |
462 | 293 |
294 /* FRAME_X_MOUSE_P (f) = 0; */ | |
295 va_run_hook_with_args (Qmouse_leave_frame_hook, 1, frame); | |
296 } | |
297 break; | |
298 | |
299 case GDK_VISIBILITY_NOTIFY: /* window visiblity has changed */ | |
300 if (event->visibility.window == GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))) | |
301 { | |
302 FRAME_GTK_TOTALLY_VISIBLE_P (f) = | |
303 (event->visibility.state == GDK_VISIBILITY_UNOBSCURED); | |
304 /* Note that the fvwm pager only sends VisibilityNotify when | |
305 changing pages. Is this all we need to do ? JV */ | |
306 /* Nope. We must at least trigger a redisplay here. | |
307 Since this case seems similar to MapNotify, I've | |
308 factored out some code to change_frame_visibility(). | |
309 This triggers the necessary redisplay and runs | |
310 (un)map-frame-hook. - dkindred@cs.cmu.edu */ | |
311 /* Changed it again to support the tristate visibility flag */ | |
312 change_frame_visibility (f, (event->visibility.state | |
313 != GDK_VISIBILITY_FULLY_OBSCURED) ? 1 : -1); | |
314 } | |
315 break; | |
316 | |
317 default: | |
318 break; | |
319 } | |
320 } | |
321 | |
322 /************************************************************************/ | |
323 /* Gtk to Emacs event conversion */ | |
324 /************************************************************************/ | |
325 | |
326 static int | |
327 keysym_obeys_caps_lock_p (guint sym, struct device *d) | |
328 { | |
329 struct gtk_device *gd = DEVICE_GTK_DATA (d); | |
330 /* Eeeeevil hack. Don't apply Caps_Lock to things that aren't alphabetic | |
331 characters, where "alphabetic" means something more than simply A-Z. | |
332 That is, if Caps_Lock is down, typing ESC doesn't produce Shift-ESC. | |
333 But if shift-lock is down, then it does. */ | |
334 if (gd->lock_interpretation == GDK_Shift_Lock) | |
335 return 1; | |
336 | |
337 return | |
338 ((sym >= GDK_A) && (sym <= GDK_Z)) || | |
339 ((sym >= GDK_a) && (sym <= GDK_z)) || | |
340 ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis)) || | |
341 ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis)) || | |
342 ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn)) || | |
343 ((sym >= GDK_oslash) && (sym <= GDK_thorn)); | |
344 } | |
345 | |
346 static void | |
347 set_last_server_timestamp (struct device *d, GdkEvent *gdk_event) | |
348 { | |
349 guint32 t; | |
350 switch (gdk_event->type) | |
351 { | |
352 case GDK_KEY_PRESS: | |
353 case GDK_KEY_RELEASE: t = gdk_event->key.time; break; | |
354 case GDK_BUTTON_PRESS: | |
355 case GDK_2BUTTON_PRESS: | |
356 case GDK_3BUTTON_PRESS: | |
357 case GDK_BUTTON_RELEASE: t = gdk_event->button.time; break; | |
358 case GDK_ENTER_NOTIFY: | |
359 case GDK_LEAVE_NOTIFY: t = gdk_event->crossing.time; break; | |
360 case GDK_MOTION_NOTIFY: t = gdk_event->motion.time; break; | |
361 case GDK_PROPERTY_NOTIFY: t = gdk_event->property.time; break; | |
362 case GDK_SELECTION_CLEAR: | |
363 case GDK_SELECTION_REQUEST: | |
364 case GDK_SELECTION_NOTIFY: t = gdk_event->selection.time; break; | |
365 default: return; | |
366 } | |
367 DEVICE_GTK_LAST_SERVER_TIMESTAMP (d) = t; | |
368 } | |
369 | |
370 static Lisp_Object | |
371 gtk_keysym_to_emacs_keysym (guint keysym, int simple_p) | |
372 { | |
373 char *name; | |
374 if (keysym >= GDK_exclam && keysym <= GDK_asciitilde) | |
375 /* We must assume that the X keysym numbers for the ASCII graphic | |
376 characters are the same as their ASCII codes. */ | |
377 return make_char (keysym); | |
378 | |
379 switch (keysym) | |
380 { | |
381 /* These would be handled correctly by the default case, but by | |
382 special-casing them here we don't garbage a string or call | |
383 intern(). */ | |
384 case GDK_BackSpace: return QKbackspace; | |
385 case GDK_Tab: return QKtab; | |
386 case GDK_Linefeed: return QKlinefeed; | |
387 case GDK_Return: return QKreturn; | |
388 case GDK_Escape: return QKescape; | |
389 case GDK_space: return QKspace; | |
390 case GDK_Delete: return QKdelete; | |
391 case 0: return Qnil; | |
392 default: | |
393 if (simple_p) return Qnil; | |
394 /* !!#### not Mule-ized */ | |
395 name = gdk_keyval_name (keysym); | |
396 if (!name || !name[0]) | |
397 /* This happens if there is a mismatch between the Xlib of | |
398 XEmacs and the Xlib of the X server... | |
399 | |
400 Let's hard-code in some knowledge of common keysyms introduced | |
401 in recent X11 releases. Snarfed from X11/keysymdef.h | |
402 | |
403 Probably we should add some stuff here for X11R6. */ | |
404 switch (keysym) | |
405 { | |
406 case 0xFF95: return KEYSYM ("kp-home"); | |
407 case 0xFF96: return KEYSYM ("kp-left"); | |
408 case 0xFF97: return KEYSYM ("kp-up"); | |
409 case 0xFF98: return KEYSYM ("kp-right"); | |
410 case 0xFF99: return KEYSYM ("kp-down"); | |
411 case 0xFF9A: return KEYSYM ("kp-prior"); | |
412 case 0xFF9B: return KEYSYM ("kp-next"); | |
413 case 0xFF9C: return KEYSYM ("kp-end"); | |
414 case 0xFF9D: return KEYSYM ("kp-begin"); | |
415 case 0xFF9E: return KEYSYM ("kp-insert"); | |
416 case 0xFF9F: return KEYSYM ("kp-delete"); | |
417 | |
418 case 0x1005FF10: return KEYSYM ("SunF36"); /* labeled F11 */ | |
419 case 0x1005FF11: return KEYSYM ("SunF37"); /* labeled F12 */ | |
420 default: | |
421 { | |
422 char buf [64]; | |
423 sprintf (buf, "unknown-keysym-0x%X", (int) keysym); | |
424 return KEYSYM (buf); | |
425 } | |
426 } | |
427 /* If it's got a one-character name, that's good enough. */ | |
428 if (!name[1]) | |
429 return make_char (name[0]); | |
430 | |
431 /* If it's in the "Keyboard" character set, downcase it. | |
432 The case of those keysyms is too totally random for us to | |
433 force anyone to remember them. | |
434 The case of the other character sets is significant, however. | |
435 */ | |
436 if ((((unsigned int) keysym) & (~0x1FF)) == ((unsigned int) 0xFE00)) | |
437 { | |
438 char buf [255]; | |
439 char *s1, *s2; | |
440 for (s1 = name, s2 = buf; *s1; s1++, s2++) { | |
441 if (*s1 == '_') { | |
442 *s2 = '-'; | |
443 } else { | |
444 *s2 = tolower (* (unsigned char *) s1); | |
445 } | |
446 } | |
447 *s2 = 0; | |
448 return KEYSYM (buf); | |
449 } | |
450 return KEYSYM (name); | |
451 } | |
452 } | |
453 | |
454 static Lisp_Object | |
455 gtk_to_emacs_keysym (struct device *d, GdkEventKey *event, int simple_p) | |
456 /* simple_p means don't try too hard (ASCII only) */ | |
457 { | |
458 if (event->length != 1) | |
771 | 459 { |
462 | 460 /* Generate multiple emacs events */ |
867 | 461 Ichar ch; |
462 | 462 Lisp_Object instream, fb_instream; |
463 Lstream *istr; | |
464 struct gcpro gcpro1, gcpro2; | |
465 | |
466 fb_instream = | |
771 | 467 make_fixed_buffer_input_stream ((unsigned char *) event->string, event->length); |
462 | 468 |
771 | 469 /* #### Use get_coding_system_for_text_file |
470 (Vcomposed_input_coding_system, 0) */ | |
462 | 471 instream = |
771 | 472 make_coding_input_stream (XLSTREAM (fb_instream), |
800 | 473 Qundecided, CODING_DECODE, 0); |
462 | 474 |
475 istr = XLSTREAM (instream); | |
476 | |
477 GCPRO2 (instream, fb_instream); | |
867 | 478 while ((ch = Lstream_get_ichar (istr)) != EOF) |
771 | 479 { |
462 | 480 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1204 | 481 Lisp_Event *ev = XEVENT (emacs_event); |
482 ev->channel = DEVICE_CONSOLE (d); | |
462 | 483 ev->timestamp = event->time; |
1204 | 484 XSET_EVENT_TYPE (emacs_event, key_press_event); |
485 XSET_EVENT_KEY_MODIFIERS (emacs_event, 0); | |
486 XSET_EVENT_KEY_KEYSYM (emacs_event, make_char (ch)); | |
487 enqueue_dispatch_event (emacs_event); | |
771 | 488 } |
462 | 489 Lstream_close (istr); |
490 UNGCPRO; | |
491 Lstream_delete (istr); | |
492 Lstream_delete (XLSTREAM (fb_instream)); | |
493 if (IS_MODIFIER_KEY (event->keyval) || (event->keyval == GDK_Mode_switch)) | |
771 | 494 return (Qnil); |
462 | 495 return (gtk_keysym_to_emacs_keysym (event->keyval, simple_p)); |
771 | 496 } |
462 | 497 else |
771 | 498 { |
462 | 499 if (IS_MODIFIER_KEY (event->keyval) || (event->keyval == GDK_Mode_switch)) |
771 | 500 return (Qnil); |
462 | 501 return (gtk_keysym_to_emacs_keysym (event->keyval, simple_p)); |
771 | 502 } |
462 | 503 } |
504 | |
505 | |
506 /************************************************************************/ | |
507 /* timeout events */ | |
508 /************************************************************************/ | |
509 | |
510 static int timeout_id_tick; | |
511 | |
853 | 512 struct GTK_timeout |
513 { | |
514 int id; | |
515 guint timeout_id; | |
516 struct GTK_timeout *next; | |
462 | 517 } *pending_timeouts, *completed_timeouts; |
518 | |
519 struct GTK_timeout_blocktype | |
520 { | |
521 Blocktype_declare (struct GTK_timeout); | |
522 } *the_GTK_timeout_blocktype; | |
523 | |
524 /* called by the gtk main loop */ | |
525 static gint | |
526 gtk_timeout_callback (gpointer closure) | |
527 { | |
528 struct GTK_timeout *timeout = (struct GTK_timeout *) closure; | |
529 struct GTK_timeout *t2 = pending_timeouts; | |
530 | |
531 /* Remove this one from the list of pending timeouts */ | |
532 if (t2 == timeout) | |
533 pending_timeouts = pending_timeouts->next; | |
534 else | |
535 { | |
536 while (t2->next && t2->next != timeout) t2 = t2->next; | |
537 assert (t2->next); | |
538 t2->next = t2->next->next; | |
539 } | |
540 /* Add this one to the list of completed timeouts */ | |
541 timeout->next = completed_timeouts; | |
542 completed_timeouts = timeout; | |
853 | 543 return FALSE; |
462 | 544 } |
545 | |
546 static int | |
547 emacs_gtk_add_timeout (EMACS_TIME thyme) | |
548 { | |
549 struct GTK_timeout *timeout = Blocktype_alloc (the_GTK_timeout_blocktype); | |
550 EMACS_TIME current_time; | |
551 int milliseconds; | |
552 | |
553 timeout->id = timeout_id_tick++; | |
554 timeout->next = pending_timeouts; | |
555 pending_timeouts = timeout; | |
556 EMACS_GET_TIME (current_time); | |
557 EMACS_SUB_TIME (thyme, thyme, current_time); | |
558 milliseconds = EMACS_SECS (thyme) * 1000 + | |
559 EMACS_USECS (thyme) / 1000; | |
560 if (milliseconds < 1) | |
561 milliseconds = 1; | |
562 timeout->timeout_id = gtk_timeout_add (milliseconds, | |
563 gtk_timeout_callback, | |
564 (gpointer) timeout); | |
565 return timeout->id; | |
566 } | |
567 | |
568 static void | |
569 emacs_gtk_remove_timeout (int id) | |
570 { | |
571 struct GTK_timeout *timeout, *t2; | |
572 | |
573 timeout = NULL; | |
574 | |
575 /* Find the timeout on the list of pending ones, if it's still there. */ | |
576 if (pending_timeouts) | |
577 { | |
578 if (id == pending_timeouts->id) | |
579 { | |
580 timeout = pending_timeouts; | |
581 pending_timeouts = pending_timeouts->next; | |
582 } | |
583 else | |
584 { | |
585 t2 = pending_timeouts; | |
586 while (t2->next && t2->next->id != id) t2 = t2->next; | |
587 if ( t2->next) /*found it */ | |
588 { | |
589 timeout = t2->next; | |
590 t2->next = t2->next->next; | |
591 } | |
592 } | |
593 /* if it was pending, we have removed it from the list */ | |
594 if (timeout) | |
595 gtk_timeout_remove (timeout->timeout_id); | |
596 } | |
597 | |
598 /* It could be that the call back was already called but we didn't convert | |
599 into an Emacs event yet */ | |
600 if (!timeout && completed_timeouts) | |
601 { | |
602 /* Code duplication! */ | |
603 if (id == completed_timeouts->id) | |
604 { | |
605 timeout = completed_timeouts; | |
606 completed_timeouts = completed_timeouts->next; | |
607 } | |
608 else | |
609 { | |
610 t2 = completed_timeouts; | |
611 while (t2->next && t2->next->id != id) t2 = t2->next; | |
612 if ( t2->next) /*found it */ | |
613 { | |
614 timeout = t2->next; | |
615 t2->next = t2->next->next; | |
616 } | |
617 } | |
618 } | |
619 | |
620 /* If we found the thing on the lists of timeouts, | |
621 and removed it, deallocate | |
622 */ | |
623 if (timeout) | |
624 Blocktype_free (the_GTK_timeout_blocktype, timeout); | |
625 } | |
626 | |
627 static void | |
628 gtk_timeout_to_emacs_event (struct Lisp_Event *emacs_event) | |
629 { | |
630 struct GTK_timeout *timeout = completed_timeouts; | |
631 assert (timeout); | |
632 completed_timeouts = completed_timeouts->next; | |
633 /* timeout events have nil as channel */ | |
1204 | 634 set_event_type (emacs_event, timeout_event); |
635 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### wrong!! */ | |
636 SET_EVENT_TIMEOUT_INTERVAL_ID (emacs_event, timeout->id); | |
637 SET_EVENT_TIMEOUT_FUNCTION (emacs_event, Qnil); | |
638 SET_EVENT_TIMEOUT_OBJECT (emacs_event, Qnil); | |
462 | 639 Blocktype_free (the_GTK_timeout_blocktype, timeout); |
640 } | |
641 | |
642 | |
643 /************************************************************************/ | |
644 /* process and tty events */ | |
645 /************************************************************************/ | |
646 | |
647 struct what_is_ready_closure | |
648 { | |
649 int fd; | |
650 Lisp_Object what; | |
651 gint id; | |
652 }; | |
653 | |
654 static Lisp_Object *filedesc_with_input; | |
655 static struct what_is_ready_closure **filedesc_to_what_closure; | |
656 | |
657 static void | |
658 init_what_input_once (void) | |
659 { | |
660 int i; | |
661 | |
662 filedesc_with_input = xnew_array (Lisp_Object, MAXDESC); | |
663 filedesc_to_what_closure = | |
664 xnew_array (struct what_is_ready_closure *, MAXDESC); | |
665 | |
666 for (i = 0; i < MAXDESC; i++) | |
667 { | |
668 filedesc_to_what_closure[i] = 0; | |
669 filedesc_with_input[i] = Qnil; | |
670 } | |
671 | |
672 process_events_occurred = 0; | |
673 tty_events_occurred = 0; | |
674 } | |
675 | |
676 static void | |
677 mark_what_as_being_ready (struct what_is_ready_closure *closure) | |
678 { | |
679 if (NILP (filedesc_with_input[closure->fd])) | |
680 { | |
681 SELECT_TYPE temp_mask; | |
682 FD_ZERO (&temp_mask); | |
683 FD_SET (closure->fd, &temp_mask); | |
684 /* Check to make sure there's *really* input available. | |
685 Sometimes things seem to get confused and this gets called | |
686 for the tty fd when there's really only input available | |
687 on some process's fd. (It will subsequently get called | |
688 for that process's fd, so returning without setting any | |
689 flags will take care of it.) To see the problem, uncomment | |
690 the stderr_out below, turn NORMAL_QUIT_CHECK_TIMEOUT_MSECS | |
691 down to 25, do sh -c 'xemacs -nw -q -f shell 2>/tmp/log' | |
692 and press return repeatedly. (Seen under AIX & Linux.) | |
693 -dkindred@cs.cmu.edu */ | |
694 if (!poll_fds_for_input (temp_mask)) | |
695 { | |
696 #if 0 | |
697 stderr_out ("mark_what_as_being_ready: no input available (fd=%d)\n", | |
698 closure->fd); | |
699 #endif | |
700 return; | |
701 } | |
702 filedesc_with_input[closure->fd] = closure->what; | |
703 if (PROCESSP (closure->what)) | |
853 | 704 /* Don't increment this if the current process is already marked |
705 * as having input. */ | |
706 process_events_occurred++; | |
462 | 707 else |
853 | 708 tty_events_occurred++; |
462 | 709 } |
710 } | |
711 | |
712 static void | |
2286 | 713 gtk_what_callback (gpointer closure, gint UNUSED (source), |
714 GdkInputCondition UNUSED (why)) | |
462 | 715 { |
716 /* If closure is 0, then we got a fake event from a signal handler. | |
717 The only purpose of this is to make XtAppProcessEvent() stop | |
718 blocking. */ | |
719 if (closure) | |
720 mark_what_as_being_ready ((struct what_is_ready_closure *) closure); | |
721 else | |
722 { | |
723 fake_event_occurred++; | |
724 drain_signal_event_pipe (); | |
725 } | |
726 } | |
727 | |
728 static void | |
729 select_filedesc (int fd, Lisp_Object what) | |
730 { | |
731 struct what_is_ready_closure *closure; | |
732 | |
733 /* If somebody is trying to select something that's already selected | |
734 for, then something went wrong. The generic routines ought to | |
735 detect this and error before here. */ | |
736 assert (!filedesc_to_what_closure[fd]); | |
737 | |
738 closure = xnew (struct what_is_ready_closure); | |
739 closure->fd = fd; | |
740 closure->what = what; | |
741 closure->id = gdk_input_add (fd, GDK_INPUT_READ, | |
742 (GdkInputFunction) gtk_what_callback, closure); | |
743 filedesc_to_what_closure[fd] = closure; | |
744 } | |
745 | |
746 static void | |
747 unselect_filedesc (int fd) | |
748 { | |
749 struct what_is_ready_closure *closure = filedesc_to_what_closure[fd]; | |
750 | |
751 assert (closure); | |
752 if (!NILP (filedesc_with_input[fd])) | |
753 { | |
754 /* We are unselecting this process before we have drained the rest of | |
755 the input from it, probably from status_notify() in the command loop. | |
756 This can happen like so: | |
757 | |
758 - We are waiting in XtAppNextEvent() | |
759 - Process generates output | |
760 - Process is marked as being ready | |
761 - Process dies, SIGCHLD gets generated before we return (!?) | |
762 It could happen I guess. | |
763 - sigchld_handler() marks process as dead | |
764 - Somehow we end up getting a new KeyPress event on the queue | |
765 at the same time (I'm really so sure how that happens but I'm | |
766 not sure it can't either so let's assume it can...). | |
767 - Key events have priority so we return that instead of the proc. | |
768 - Before dispatching the lisp key event we call status_notify() | |
769 - Which deselects the process that SIGCHLD marked as dead. | |
770 | |
771 Thus we never remove it from _with_input and turn it into a lisp | |
772 event, so we need to do it here. But this does not mean that we're | |
773 throwing away the last block of output - status_notify() has already | |
774 taken care of running the proc filter or whatever. | |
775 */ | |
776 filedesc_with_input[fd] = Qnil; | |
777 if (PROCESSP (closure->what)) | |
778 { | |
779 assert (process_events_occurred > 0); | |
780 process_events_occurred--; | |
781 } | |
782 else | |
783 { | |
784 assert (tty_events_occurred > 0); | |
785 tty_events_occurred--; | |
786 } | |
787 } | |
788 gdk_input_remove (closure->id); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4962
diff
changeset
|
789 xfree (closure); |
462 | 790 filedesc_to_what_closure[fd] = 0; |
791 } | |
792 | |
793 static void | |
853 | 794 emacs_gtk_select_process (Lisp_Process *process, int doin, int doerr) |
462 | 795 { |
853 | 796 Lisp_Object proc; |
797 int infd, errfd; | |
798 | |
799 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
800 | |
801 proc = wrap_process (process); | |
802 if (doin) | |
803 select_filedesc (infd, proc); | |
804 if (doerr) | |
805 select_filedesc (errfd, proc); | |
806 } | |
462 | 807 |
853 | 808 static void |
809 emacs_gtk_unselect_process (Lisp_Process *process, int doin, int doerr) | |
810 { | |
811 int infd, errfd; | |
812 | |
813 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
814 | |
815 if (doin) | |
816 unselect_filedesc (infd); | |
817 if (doerr) | |
818 unselect_filedesc (errfd); | |
462 | 819 } |
820 | |
821 static void | |
853 | 822 emacs_gtk_create_io_streams (void *inhandle, void *outhandle, |
823 void *errhandle, Lisp_Object *instream, | |
824 Lisp_Object *outstream, | |
825 Lisp_Object *errstream, | |
826 USID *in_usid, | |
827 USID *err_usid, | |
828 int flags) | |
462 | 829 { |
853 | 830 event_stream_unixoid_create_io_streams |
831 (inhandle, outhandle, errhandle, instream, outstream, | |
832 errstream, in_usid, err_usid, flags); | |
833 if (*in_usid != USID_ERROR) | |
834 *in_usid = USID_DONTHASH; | |
835 if (*err_usid != USID_ERROR) | |
836 *err_usid = USID_DONTHASH; | |
462 | 837 } |
838 | |
853 | 839 static void |
840 emacs_gtk_delete_io_streams (Lisp_Object instream, | |
841 Lisp_Object outstream, | |
842 Lisp_Object errstream, | |
843 USID *in_usid, | |
844 USID *err_usid) | |
462 | 845 { |
853 | 846 event_stream_unixoid_delete_io_streams |
847 (instream, outstream, errstream, in_usid, err_usid); | |
848 *in_usid = USID_DONTHASH; | |
849 *err_usid = USID_DONTHASH; | |
462 | 850 } |
851 | |
852 /* This is called from GC when a process object is about to be freed. | |
853 If we've still got pointers to it in this file, we're gonna lose hard. | |
854 */ | |
855 void | |
2286 | 856 debug_process_finalization (struct Lisp_Process *UNUSED (p)) |
462 | 857 { |
858 #if 0 /* #### */ | |
859 int i; | |
860 Lisp_Object instr, outstr; | |
861 | |
862 get_process_streams (p, &instr, &outstr); | |
863 /* if it still has fds, then it hasn't been killed yet. */ | |
864 assert (NILP(instr)); | |
865 assert (NILP(outstr)); | |
866 /* Better not still be in the "with input" table; we know it's got no fds. */ | |
867 for (i = 0; i < MAXDESC; i++) | |
868 { | |
869 Lisp_Object process = filedesc_fds_with_input [i]; | |
870 assert (!PROCESSP (process) || XPROCESS (process) != p); | |
871 } | |
872 #endif | |
873 } | |
874 | |
875 static void | |
876 gtk_process_to_emacs_event (struct Lisp_Event *emacs_event) | |
877 { | |
878 int i; | |
879 | |
880 assert (process_events_occurred > 0); | |
1204 | 881 |
462 | 882 for (i = 0; i < MAXDESC; i++) |
883 { | |
1204 | 884 Lisp_Object process = filedesc_with_input[i]; |
462 | 885 if (PROCESSP (process)) |
1204 | 886 { |
887 filedesc_with_input[i] = Qnil; | |
888 process_events_occurred--; | |
889 /* process events have nil as channel */ | |
890 set_event_type (emacs_event, process_event); | |
891 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### */ | |
892 SET_EVENT_PROCESS_PROCESS (emacs_event, process); | |
893 return; | |
894 } | |
462 | 895 } |
2500 | 896 ABORT (); |
462 | 897 } |
898 | |
899 static void | |
900 emacs_gtk_select_console (struct console *con) | |
901 { | |
902 Lisp_Object console; | |
903 int infd; | |
904 | |
905 if (CONSOLE_GTK_P (con)) | |
906 return; /* Gtk consoles are automatically selected for when we initialize them */ | |
907 infd = event_stream_unixoid_select_console (con); | |
793 | 908 console = wrap_console (con); |
462 | 909 select_filedesc (infd, console); |
910 } | |
911 | |
912 static void | |
913 emacs_gtk_unselect_console (struct console *con) | |
914 { | |
915 Lisp_Object console; | |
916 int infd; | |
917 | |
918 if (CONSOLE_GTK_P (con)) | |
919 return; /* X consoles are automatically selected for when we initialize them */ | |
920 infd = event_stream_unixoid_unselect_console (con); | |
793 | 921 console = wrap_console (con); |
462 | 922 unselect_filedesc (infd); |
923 } | |
924 | |
925 /* read an event from a tty, if one is available. Returns non-zero | |
926 if an event was available. Note that when this function is | |
927 called, there should always be a tty marked as ready for input. | |
928 However, the input condition might actually be EOF, so there | |
929 may not really be any input available. (In this case, | |
930 read_event_from_tty_or_stream_desc() will arrange for the TTY device | |
931 to be deleted.) */ | |
932 | |
933 static int | |
934 gtk_tty_to_emacs_event (struct Lisp_Event *emacs_event) | |
935 { | |
936 int i; | |
937 | |
938 assert (tty_events_occurred > 0); | |
939 for (i = 0; i < MAXDESC; i++) | |
940 { | |
941 Lisp_Object console = filedesc_with_input[i]; | |
942 if (CONSOLEP (console)) | |
943 { | |
944 assert (tty_events_occurred > 0); | |
945 tty_events_occurred--; | |
946 filedesc_with_input[i] = Qnil; | |
771 | 947 if (read_event_from_tty_or_stream_desc (emacs_event, |
948 XCONSOLE (console))) | |
462 | 949 return 1; |
950 } | |
951 } | |
952 | |
953 return 0; | |
954 } | |
955 | |
956 | |
957 /************************************************************************/ | |
958 /* Drag 'n Drop handling */ | |
959 /************************************************************************/ | |
960 #ifdef HAVE_DRAGNDROP | |
961 #define TARGET_URI_LIST 0x00 | |
962 #define TARGET_TEXT_PLAIN 0x01 | |
963 #define TARGET_FILE_NAME 0x02 | |
964 #define TARGET_NETSCAPE 0x03 | |
965 | |
966 static GdkAtom preferred_targets[10]; | |
967 | |
968 void | |
969 dragndrop_data_received (GtkWidget *widget, | |
970 GdkDragContext *context, | |
971 gint x, | |
972 gint y, | |
973 GtkSelectionData *data, | |
2286 | 974 guint UNUSED (info), |
462 | 975 guint time) |
976 { | |
977 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
978 struct device *d = gtk_any_window_to_device (widget->window); | |
979 struct frame *f = gtk_any_widget_or_parent_to_frame (d, widget); | |
980 struct Lisp_Event *ev = XEVENT (event); | |
981 Lisp_Object l_type = Qnil, l_data = Qnil; | |
982 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
983 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
984 | |
985 GCPRO4 (l_type, l_data, l_dndlist, l_item); | |
986 | |
1204 | 987 set_event_type (ev, misc_user_event); |
988 SET_EVENT_CHANNEL (ev, wrap_frame (f)); | |
989 SET_EVENT_TIMESTAMP (ev, time); | |
990 SET_EVENT_MISC_USER_X (ev, x); | |
991 SET_EVENT_MISC_USER_Y (ev, y); | |
462 | 992 |
993 if (data->type == preferred_targets[TARGET_URI_LIST]) | |
994 { | |
995 /* newline-separated list of URLs */ | |
996 int start, end; | |
997 const char *string_data = (char *) data->data; | |
998 | |
999 l_type = Qdragdrop_URL; | |
1000 | |
1001 for (start = 0, end = 0; string_data && string_data[end]; end++) | |
1002 { | |
1003 if ((string_data[end] == '\r') && (string_data[end+1] == '\n')) | |
1004 { | |
1005 l_item = make_string (&string_data[start], end - start); | |
1006 l_dndlist = Fcons (l_item, l_dndlist); | |
1007 ++end; | |
1008 start = ++end; | |
1009 } | |
1010 } | |
1011 } | |
1012 else if (data->type == preferred_targets[TARGET_TEXT_PLAIN]) | |
1013 { | |
1014 /* Arbitrary string */ | |
1015 l_type = Qdragdrop_MIME; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1016 l_dndlist = list1 (list3 (list1 (build_ascstring ("text/plain")), |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1017 build_ascstring ("8_bit"), |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
1018 make_extstring (data->data, |
462 | 1019 strlen ((char *)data->data), |
1020 Qctext))); | |
1021 } | |
1022 else if (data->type == preferred_targets[TARGET_FILE_NAME]) | |
1023 { | |
1024 /* Random filename */ | |
1025 char *hurl = dnd_url_hexify_string (data->data, "file:"); | |
1026 | |
867 | 1027 l_dndlist = list1 (make_string ((Ibyte *)hurl, strlen (hurl))); |
462 | 1028 l_type = Qdragdrop_URL; |
1029 | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4962
diff
changeset
|
1030 xfree (hurl); |
462 | 1031 } |
1032 else if (data->type == preferred_targets[TARGET_NETSCAPE]) | |
1033 { | |
1034 /* Single URL */ | |
1035 l_dndlist = list1 (make_string ((Extbyte *)data->data, | |
1036 strlen ((char *)data->data))); | |
1037 l_type = Qdragdrop_URL; | |
1038 } | |
1039 else | |
1040 { | |
1041 /* Unknown type - what to do? | |
1042 We just pass it up to lisp - we already have a mime type. | |
1043 */ | |
1044 l_type = Qdragdrop_MIME; | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
1045 l_dndlist = list1 (list3 (list1 (build_cistring (gdk_atom_name (data->type))), |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1046 build_ascstring ("8bit"), |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
1047 make_extstring ((Extbyte *) data->data, |
462 | 1048 data->length, Qbinary))); |
1049 } | |
1050 | |
1204 | 1051 |
1052 SET_EVENT_MISC_USER_FUNCTION (ev, Qdragdrop_drop_dispatch); | |
1053 SET_EVENT_MISC_USER_OBJECT (ev, Fcons (l_type, l_dndlist)); | |
462 | 1054 |
1055 UNGCPRO; | |
1056 | |
1057 gtk_drag_finish (context, TRUE, FALSE, time); | |
1204 | 1058 enqueue_dispatch_event (event); |
462 | 1059 } |
1060 | |
1061 gboolean | |
2286 | 1062 dragndrop_dropped (GtkWidget *UNUSED (widget), |
462 | 1063 GdkDragContext *drag_context, |
2286 | 1064 gint UNUSED (x), |
1065 gint UNUSED (y), | |
462 | 1066 guint time, |
1067 gpointer user_data) | |
1068 { | |
1069 /* Netscape drops things like: | |
1070 STRING | |
1071 _SGI_ICON | |
1072 _SGI_ICON_TYPE | |
1073 SGI_FILE | |
1074 FILE_NAME | |
1075 _NETSCAPE_URL | |
1076 | |
1077 gmc drops things like | |
1078 application/x-mc-desktop-icon | |
1079 text/uri-list | |
1080 text/plain | |
1081 _NETSCAPE_URL | |
1082 | |
1083 We prefer: | |
1084 text/uri-list | |
1085 text/plain | |
1086 FILE_NAME | |
1087 _NETSCAPE_URL | |
1088 first one | |
1089 */ | |
1090 GdkAtom found = 0; | |
1091 GList *list = drag_context->targets; | |
1092 | |
1093 int i; | |
1094 | |
1095 if (!preferred_targets[0]) | |
1096 { | |
1097 preferred_targets[TARGET_URI_LIST] = gdk_atom_intern ("text/uri-list", FALSE); | |
1098 preferred_targets[TARGET_TEXT_PLAIN] = gdk_atom_intern ("text/plain", FALSE); | |
1099 preferred_targets[TARGET_FILE_NAME] = gdk_atom_intern ("FILE_NAME", FALSE); | |
1100 preferred_targets[TARGET_NETSCAPE] = gdk_atom_intern ("_NETSCAPE_URL", FALSE); | |
1101 } | |
1102 | |
1103 #if 0 | |
1104 stderr_out ("Drop info available in the following formats: \n"); | |
1105 while (list) | |
1106 { | |
1107 stderr_out ("\t%s\n", gdk_atom_name ((GdkAtom)list->data)); | |
1108 list = list->next; | |
1109 } | |
1110 list = drag_context->targets; | |
1111 #endif | |
1112 | |
1113 while (list && !found) | |
1114 { | |
1115 for (i = 0; preferred_targets[i] && !found; i++) | |
1116 { | |
1117 if ((GdkAtom) list->data == preferred_targets[i]) | |
1118 { | |
1119 found = (GdkAtom) list->data; | |
1120 } | |
1121 } | |
1122 list = list->next; | |
1123 } | |
1124 | |
1125 if (!found) | |
1126 { | |
1127 found = (GdkAtom) drag_context->targets->data; | |
1128 } | |
1129 | |
1130 gtk_drag_get_data (GTK_WIDGET (user_data), drag_context, found, time); | |
1131 return (TRUE); | |
1132 } | |
1133 #endif /* HAVE_DRAGNDROP */ | |
1134 | |
1135 | |
1136 /************************************************************************/ | |
1137 /* get the next event from gtk */ | |
1138 /************************************************************************/ | |
1139 | |
1140 /* This business exists because menu events "happen" when | |
1141 menubar_selection_callback() is called from somewhere deep | |
1142 within XtAppProcessEvent in emacs_Xt_next_event(). The | |
1143 callback needs to terminate the modal loop in that function | |
1144 or else it will continue waiting until another event is | |
1145 received. | |
1146 | |
1147 Same business applies to scrollbar events. */ | |
1148 | |
1149 void | |
1150 signal_special_gtk_user_event (Lisp_Object channel, Lisp_Object function, | |
1151 Lisp_Object object) | |
1152 { | |
1153 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1154 | |
1204 | 1155 XSET_EVENT_TYPE (event, misc_user_event); |
1156 XSET_EVENT_CHANNEL (event, channel); | |
1157 XSET_EVENT_MISC_USER_FUNCTION (event, function); | |
1158 XSET_EVENT_MISC_USER_OBJECT (event, object); | |
1159 enqueue_dispatch_event (event); | |
462 | 1160 } |
1161 | |
1162 static void | |
1163 emacs_gtk_next_event (struct Lisp_Event *emacs_event) | |
1164 { | |
1165 we_didnt_get_an_event: | |
1166 | |
1167 while (NILP (dispatch_event_queue) && | |
1168 !completed_timeouts && | |
1169 !fake_event_occurred && | |
1170 !process_events_occurred && | |
1171 !tty_events_occurred) | |
1172 { | |
1292 | 1173 #ifdef WIN32_ANY |
1174 mswindows_is_blocking = 1; | |
1175 #endif | |
1176 gtk_main_iteration (); | |
1177 #ifdef WIN32_ANY | |
1178 mswindows_is_blocking = 0; | |
1179 #endif | |
462 | 1180 } |
1181 | |
1182 if (!NILP (dispatch_event_queue)) | |
1183 { | |
1184 Lisp_Object event, event2; | |
793 | 1185 event2 = wrap_event (emacs_event); |
1204 | 1186 event = dequeue_dispatch_event (); |
462 | 1187 Fcopy_event (event, event2); |
1188 Fdeallocate_event (event); | |
1189 } | |
1190 else if (tty_events_occurred) | |
1191 { | |
1192 if (!gtk_tty_to_emacs_event (emacs_event)) | |
1193 goto we_didnt_get_an_event; | |
1194 } | |
1195 else if (completed_timeouts) | |
1196 gtk_timeout_to_emacs_event (emacs_event); | |
1197 else if (fake_event_occurred) | |
1198 { | |
1199 /* A dummy event, so that a cycle of the command loop will occur. */ | |
1200 fake_event_occurred = 0; | |
1201 /* eval events have nil as channel */ | |
1204 | 1202 set_event_type (emacs_event, eval_event); |
1203 SET_EVENT_EVAL_FUNCTION (emacs_event, Qidentity); | |
1204 SET_EVENT_EVAL_OBJECT (emacs_event, Qnil); | |
462 | 1205 } |
1206 else /* if (process_events_occurred) */ | |
1207 gtk_process_to_emacs_event (emacs_event); | |
1208 } | |
1209 | |
1210 int | |
1211 gtk_event_to_emacs_event (struct frame *frame, GdkEvent *gdk_event, struct Lisp_Event *emacs_event) | |
1212 { | |
1213 struct device *d = NULL; | |
1214 struct gtk_device *gd = NULL; | |
1215 gboolean accept_any_window = FALSE; | |
1216 | |
872 | 1217 /* #### Under what circumstances can this happen???? Hunt out the code that |
1218 sets frame to 0 and fix it instead. */ | |
462 | 1219 if (!frame) |
1220 { | |
872 | 1221 frame = XFRAME (Fselected_frame (get_default_device (Qgtk))); |
462 | 1222 accept_any_window = TRUE; |
1223 } | |
1224 | |
1225 d = XDEVICE (FRAME_DEVICE (frame)); | |
1226 gd = DEVICE_GTK_DATA (d); | |
1227 | |
1228 set_last_server_timestamp (d, gdk_event); | |
1229 | |
1230 switch (gdk_event->type) | |
1231 { | |
1232 /* XEmacs handles double and triple clicking on its own, and if | |
1233 we capture these events, it royally confuses the code in | |
1234 ../lisp/mouse.el */ | |
1235 case GDK_2BUTTON_PRESS: | |
1236 case GDK_3BUTTON_PRESS: | |
1237 return (0); | |
1238 | |
1239 case GDK_BUTTON_PRESS: | |
1240 case GDK_BUTTON_RELEASE: | |
1241 /* We need to ignore button events outside our main window or | |
1242 things get ugly. The standard scrollbars in Gtk try to be | |
1243 nice and pass the button press events up to the parent | |
1244 widget. This causes us no end of grief though. Effects | |
1245 range from setting point to the wrong place to selecting | |
1246 new windows. */ | |
1247 { | |
1248 GdkWindow *w = gdk_window_at_pointer (NULL, NULL); | |
1249 | |
1250 /* If you press mouse button and drag it around, and release | |
1251 it outside the window, you will get a NULL GdkWindow at | |
1252 pointer. We need to forward these events on to XEmacs so | |
1253 that the mouse selection voodoo works. | |
1254 */ | |
1255 if (w && (w != gdk_window_lookup (GDK_ROOT_WINDOW ()))) | |
1256 { | |
1257 GdkEvent ev; | |
1258 GtkWidget *wid = NULL; | |
1259 | |
1260 ev.any.window = w; | |
1261 wid = gtk_get_event_widget (&ev); | |
1262 | |
1263 if (!GTK_IS_XEMACS (wid) && !accept_any_window) | |
1264 { | |
1265 return (0); | |
1266 } | |
1267 } | |
1268 if (!accept_any_window) | |
1269 gtk_widget_grab_focus (FRAME_GTK_TEXT_WIDGET (frame)); | |
1270 } | |
1271 /* Fall through */ | |
1272 case GDK_KEY_PRESS: | |
1273 { | |
1274 unsigned int modifiers = 0; | |
1275 int shift_p, lock_p; | |
1276 gboolean key_event_p = (gdk_event->type == GDK_KEY_PRESS); | |
1277 unsigned int *state = | |
1278 key_event_p ? &gdk_event->key.state : &gdk_event->button.state; | |
1279 | |
1280 /* If this is a synthetic KeyPress or Button event, and the user | |
1281 has expressed a disinterest in this security hole, then drop | |
1282 it on the floor. */ | |
1283 /* #### BILL!!! Should this be a generic check for ANY synthetic | |
1284 event? */ | |
1285 if ((gdk_event->any.send_event) && !gtk_allow_sendevents) | |
1286 return 0; | |
1287 | |
1288 DEVICE_GTK_MOUSE_TIMESTAMP (d) = | |
1289 DEVICE_GTK_GLOBAL_MOUSE_TIMESTAMP (d) = | |
1290 key_event_p ? gdk_event->key.time : gdk_event->button.time; | |
1291 | |
1292 if (*state & GDK_CONTROL_MASK) modifiers |= XEMACS_MOD_CONTROL; | |
1293 if (*state & gd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1294 if (*state & gd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1295 if (*state & gd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1296 if (*state & gd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
1297 | |
589 | 1298 { |
1299 int numero_de_botao = -1; | |
1300 | |
1301 if (!key_event_p) | |
1302 numero_de_botao = gdk_event->button.button; | |
1303 | |
1304 /* the button gets noted either in the button or the modifiers | |
1305 field, but not both. */ | |
1306 if (numero_de_botao != 1 && (*state & GDK_BUTTON1_MASK)) | |
1307 modifiers |= XEMACS_MOD_BUTTON1; | |
1308 if (numero_de_botao != 2 && (*state & GDK_BUTTON2_MASK)) | |
1309 modifiers |= XEMACS_MOD_BUTTON2; | |
1310 if (numero_de_botao != 3 && (*state & GDK_BUTTON3_MASK)) | |
1311 modifiers |= XEMACS_MOD_BUTTON3; | |
1312 if (numero_de_botao != 4 && (*state & GDK_BUTTON4_MASK)) | |
1313 modifiers |= XEMACS_MOD_BUTTON4; | |
1314 if (numero_de_botao != 5 && (*state & GDK_BUTTON5_MASK)) | |
1315 modifiers |= XEMACS_MOD_BUTTON5; | |
1316 } | |
1317 | |
462 | 1318 /* Ignore the Caps_Lock key if: |
1319 - any other modifiers are down, so that Caps_Lock doesn't | |
1320 turn C-x into C-X, which would suck. | |
1321 - the event was a mouse event. */ | |
1322 if (modifiers || ! key_event_p) | |
1323 *state &= (~GDK_LOCK_MASK); | |
1324 | |
1325 shift_p = *state & GDK_SHIFT_MASK; | |
1326 lock_p = *state & GDK_LOCK_MASK; | |
1327 | |
1328 if (shift_p || lock_p) | |
1329 modifiers |= XEMACS_MOD_SHIFT; | |
1330 | |
1331 if (key_event_p) | |
1332 { | |
1333 GdkEventKey *key_event = &gdk_event->key; | |
1334 Lisp_Object keysym; | |
1335 | |
2081 | 1336 #ifdef HAVE_MENUBARS |
1337 /* If the user wants see if the event is a menu bar accelerator. | |
1338 The process of checking absorbs the event and starts menu | |
1339 processing so send a null event into XEmacs to make sure it | |
1340 does nothing. | |
1341 */ | |
1342 if (!NILP (Vmenu_accelerator_enabled) | |
1343 && gtk_accel_groups_activate(GTK_OBJECT (FRAME_GTK_SHELL_WIDGET(frame)), | |
1344 key_event->keyval, | |
1345 (GdkModifierType) *state)) | |
1346 { | |
1347 zero_event(emacs_event); | |
1348 return 1; | |
1349 } | |
1350 #endif | |
1351 | |
462 | 1352 /* This used to compute the frame from the given X window and |
1353 store it here, but we really don't care about the frame. */ | |
1354 emacs_event->channel = DEVICE_CONSOLE (d); | |
1355 | |
1356 /* Keysym mucking has already been done inside the | |
1357 GdkEventKey parsing */ | |
1358 keysym = gtk_to_emacs_keysym (d, key_event, 0); | |
1359 | |
1360 /* If the emacs keysym is nil, then that means that the X | |
1361 keysym was either a Modifier or NoSymbol, which | |
1362 probably means that we're in the midst of reading a | |
1363 Multi_key sequence, or a "dead" key prefix, or XIM | |
1364 input. Ignore it. */ | |
1365 if (NILP (keysym)) | |
1366 return 0; | |
1367 | |
1368 /* More Caps_Lock garbage: Caps_Lock should *only* add the | |
1369 shift modifier to two-case keys (that is, A-Z and | |
1370 related characters). So at this point (after looking up | |
1371 the keysym) if the keysym isn't a dual-case alphabetic, | |
1372 and if the caps lock key was down but the shift key | |
1373 wasn't, then turn off the shift modifier. Gag barf */ | |
1374 /* #### type lossage: assuming equivalence of emacs and | |
1375 X keysyms */ | |
1376 /* !!#### maybe fix for Mule */ | |
1377 if (lock_p && !shift_p && | |
1378 ! (CHAR_OR_CHAR_INTP (keysym) | |
1379 && keysym_obeys_caps_lock_p | |
1380 ((guint) XCHAR_OR_CHAR_INT (keysym), d))) | |
1381 modifiers &= (~XEMACS_MOD_SHIFT); | |
1382 | |
1383 /* If this key contains two distinct keysyms, that is, | |
1384 "shift" generates a different keysym than the | |
1385 non-shifted key, then don't apply the shift modifier | |
1386 bit: it's implicit. Otherwise, if there would be no | |
1387 other way to tell the difference between the shifted | |
1388 and unshifted version of this key, apply the shift bit. | |
1389 Non-graphics, like Backspace and F1 get the shift bit | |
1390 in the modifiers slot. Neither the characters "a", | |
1391 "A", "2", nor "@" normally have the shift bit set. | |
1392 However, "F1" normally does. */ | |
1393 if (modifiers & XEMACS_MOD_SHIFT) | |
1394 { | |
1395 if (CHAR_OR_CHAR_INTP (keysym)) | |
1396 { | |
1397 modifiers &= ~XEMACS_MOD_SHIFT; | |
1398 } | |
1399 } | |
1400 | |
1204 | 1401 set_event_type (emacs_event, key_press_event); |
1402 SET_EVENT_TIMESTAMP (emacs_event, key_event->time); | |
1403 SET_EVENT_KEY_MODIFIERS (emacs_event, modifiers); | |
1404 SET_EVENT_KEY_KEYSYM (emacs_event, keysym); | |
462 | 1405 } |
1406 else /* Mouse press/release event */ | |
1407 { | |
1408 GdkEventButton *button_event = &gdk_event->button; | |
1409 | |
1204 | 1410 set_event_type (emacs_event, |
1411 button_event->type == GDK_BUTTON_RELEASE ? | |
1412 button_release_event : button_press_event); | |
1413 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); | |
462 | 1414 |
1204 | 1415 SET_EVENT_BUTTON_MODIFIERS (emacs_event, modifiers); |
1416 SET_EVENT_TIMESTAMP (emacs_event, button_event->time); | |
1417 SET_EVENT_BUTTON_BUTTON (emacs_event, button_event->button); | |
2054 | 1418 SET_EVENT_BUTTON_X (emacs_event, (int) button_event->x); |
1419 SET_EVENT_BUTTON_Y (emacs_event, (int) button_event->y); | |
462 | 1420 } |
1421 } | |
1422 break; | |
1423 case GDK_KEY_RELEASE: | |
1424 return 0; | |
1425 break; | |
1426 case GDK_MOTION_NOTIFY: | |
1427 { | |
1428 GdkEventMotion *ev = &gdk_event->motion; | |
1429 unsigned int modifiers = 0; | |
1430 gint x,y; | |
1431 GdkModifierType mask; | |
1432 | |
1433 /* We use MOTION_HINT_MASK, so we will get only one motion | |
1434 event until the next time we call gdk_window_get_pointer or | |
1435 the user clicks the mouse. So call gdk_window_get_pointer | |
1436 now (meaning that the event will be in sync with the server | |
1437 just before Fnext_event() returns). If the mouse is still | |
1438 in motion, then the server will immediately generate | |
1439 exactly one more motion event, which will be on the queue | |
1440 waiting for us next time around. */ | |
1441 gdk_window_get_pointer (ev->window, &x, &y, &mask); | |
1442 | |
1443 DEVICE_GTK_MOUSE_TIMESTAMP (d) = ev->time; | |
1444 | |
1204 | 1445 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); |
1446 set_event_type (emacs_event, pointer_motion_event); | |
1447 SET_EVENT_TIMESTAMP (emacs_event, ev->time); | |
1448 SET_EVENT_MOTION_X (emacs_event, x); | |
1449 SET_EVENT_MOTION_Y (emacs_event, y); | |
1450 | |
462 | 1451 if (mask & GDK_SHIFT_MASK) modifiers |= XEMACS_MOD_SHIFT; |
1452 if (mask & GDK_CONTROL_MASK) modifiers |= XEMACS_MOD_CONTROL; | |
1453 if (mask & gd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1454 if (mask & gd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1455 if (mask & gd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1456 if (mask & gd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
589 | 1457 if (mask & GDK_BUTTON1_MASK) modifiers |= XEMACS_MOD_BUTTON1; |
1458 if (mask & GDK_BUTTON2_MASK) modifiers |= XEMACS_MOD_BUTTON2; | |
1459 if (mask & GDK_BUTTON3_MASK) modifiers |= XEMACS_MOD_BUTTON3; | |
1460 if (mask & GDK_BUTTON4_MASK) modifiers |= XEMACS_MOD_BUTTON4; | |
1461 if (mask & GDK_BUTTON5_MASK) modifiers |= XEMACS_MOD_BUTTON5; | |
1462 | |
462 | 1463 /* Currently ignores Shift_Lock but probably shouldn't |
1464 (but it definitely should ignore Caps_Lock). */ | |
1204 | 1465 SET_EVENT_MOTION_MODIFIERS (emacs_event, modifiers); |
462 | 1466 } |
1467 break; | |
1468 | |
1469 default: /* it's a magic event */ | |
1470 return (0); | |
1471 break; | |
1472 } | |
1473 return 1; | |
1474 } | |
1475 | |
1476 static const char *event_name (GdkEvent *); | |
1477 | |
1478 static gboolean | |
1479 generic_event_handler (GtkWidget *widget, GdkEvent *event) | |
1480 { | |
1481 Lisp_Object emacs_event = Qnil; | |
1482 if (!GTK_IS_XEMACS (widget)) | |
1483 { | |
1484 stderr_out ("Got a %s event for a non-XEmacs widget\n",event_name (event)); | |
1485 return (FALSE); | |
1486 } | |
1487 | |
1488 emacs_event = Fmake_event (Qnil, Qnil); | |
1489 | |
1490 if (gtk_event_to_emacs_event (GTK_XEMACS_FRAME (widget), event, XEVENT (emacs_event))) | |
1491 { | |
1204 | 1492 enqueue_dispatch_event (emacs_event); |
462 | 1493 return (TRUE); |
1494 } | |
1495 else | |
1496 { | |
1497 Fdeallocate_event (emacs_event); | |
1498 } | |
1499 return (FALSE); | |
1500 } | |
1501 | |
1416 | 1502 gint |
1503 emacs_gtk_key_event_handler (GtkWidget *widget, GdkEventKey *event) | |
462 | 1504 { |
1505 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1506 } | |
1507 | |
1416 | 1508 gint |
1509 emacs_gtk_button_event_handler (GtkWidget *widget, GdkEventButton *event) | |
462 | 1510 { |
1511 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1512 } | |
1513 | |
1416 | 1514 gint |
1515 emacs_gtk_motion_event_handler (GtkWidget *widget, GdkEventMotion *event) | |
462 | 1516 { |
1517 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1518 } | |
1519 | |
1520 gboolean | |
2286 | 1521 emacs_shell_event_handler (GtkWidget *UNUSED (wid), |
462 | 1522 GdkEvent *event, |
1523 gpointer closure) | |
1524 { | |
1525 struct frame *frame = (struct frame *) closure; | |
1526 Lisp_Object lisp_event = Fmake_event (Qnil, Qnil); | |
1527 struct Lisp_Event *emacs_event = XEVENT (lisp_event); | |
1204 | 1528 GdkEvent *gdk_event_copy = &EVENT_MAGIC_GDK_EVENT (emacs_event); |
462 | 1529 struct device *d = XDEVICE (FRAME_DEVICE (frame)); |
1530 gboolean ignore_p = FALSE; | |
1531 | |
1532 set_last_server_timestamp (d, event); | |
1533 | |
1534 #define FROB(event_member) gdk_event_copy->event_member = event->event_member | |
1535 | |
1536 switch (event->type) | |
1537 { | |
1538 case GDK_SELECTION_REQUEST: | |
1539 case GDK_SELECTION_CLEAR: | |
1540 case GDK_SELECTION_NOTIFY: FROB(selection); break; | |
1541 case GDK_PROPERTY_NOTIFY: FROB(property); break; | |
1542 case GDK_CLIENT_EVENT: FROB(client); break; | |
1543 case GDK_MAP: | |
1544 case GDK_UNMAP: FROB(any); break; | |
1545 case GDK_CONFIGURE: FROB(configure); break; | |
1546 case GDK_ENTER_NOTIFY: | |
1547 case GDK_LEAVE_NOTIFY: FROB(crossing); break; | |
1548 case GDK_FOCUS_CHANGE: FROB(focus_change); break; | |
1549 case GDK_VISIBILITY_NOTIFY: FROB(visibility); break; | |
1550 default: | |
1551 ignore_p = TRUE; | |
1552 /* Hrmm... do we really want to swallow all the other events as magic? */ | |
1553 *gdk_event_copy = *event; | |
1554 break; | |
1555 } | |
1556 #undef FROB | |
1557 | |
1558 emacs_event->event_type = magic_event; | |
793 | 1559 emacs_event->channel = wrap_frame (frame); |
462 | 1560 |
1561 if (ignore_p) | |
793 | 1562 { |
462 | 1563 stderr_out ("Ignoring event... (%s)\n", event_name (event)); |
1564 Fdeallocate_event (lisp_event); | |
1565 return (FALSE); | |
793 | 1566 } |
462 | 1567 else |
793 | 1568 { |
1204 | 1569 enqueue_dispatch_event (lisp_event); |
462 | 1570 return (TRUE); |
793 | 1571 } |
462 | 1572 } |
1573 | |
1574 | |
1575 /************************************************************************/ | |
1576 /* input pending / C-g checking */ | |
1577 /************************************************************************/ | |
1578 | |
1579 static void | |
1204 | 1580 emacs_gtk_drain_queue (void) |
462 | 1581 |
1582 { | |
1583 /* We can't just spin through here and wait for GTKs idea of the | |
1584 event queue to get empty, or the queue never gets drained. The | |
1585 situation is as follows. A process event gets signalled, we put | |
1586 it on the queue, then we go into Fnext_event(), which calls | |
1204 | 1587 emacs_gtk_drain_queue(). But gtk_events_pending() will always return |
462 | 1588 TRUE if there are file-descriptor (aka our process) events |
1589 pending. Using GDK_events_pending() only shows us windowing | |
1590 system events. | |
1591 */ | |
1592 if (GDK_DISPLAY ()) | |
1593 while (gdk_events_pending ()) | |
1594 gtk_main_iteration (); | |
1204 | 1595 |
1268 | 1596 #ifdef HAVE_TTY |
1204 | 1597 drain_tty_devices (); |
462 | 1598 #endif |
1599 } | |
1600 | |
790 | 1601 static void |
2286 | 1602 emacs_gtk_force_event_pending (struct frame* UNUSED (f)) |
790 | 1603 { |
1604 #if 0 | |
1605 stderr_out ("Force event pending called on frame %p!\n", f); | |
1606 #endif | |
1607 } | |
1608 | |
462 | 1609 |
1610 /************************************************************************/ | |
1611 /* initialization */ | |
1612 /************************************************************************/ | |
1613 | |
1614 void | |
1615 syms_of_event_gtk (void) | |
1616 { | |
1617 } | |
1618 | |
1416 | 1619 void |
1620 reinit_vars_of_event_gtk (void) | |
462 | 1621 { |
1204 | 1622 gtk_event_stream = xnew_and_zero (struct event_stream); |
462 | 1623 gtk_event_stream->event_pending_p = emacs_gtk_event_pending_p; |
1624 gtk_event_stream->next_event_cb = emacs_gtk_next_event; | |
1625 gtk_event_stream->handle_magic_event_cb= emacs_gtk_handle_magic_event; | |
788 | 1626 gtk_event_stream->format_magic_event_cb= emacs_gtk_format_magic_event; |
1627 gtk_event_stream->compare_magic_event_cb= emacs_gtk_compare_magic_event; | |
1628 gtk_event_stream->hash_magic_event_cb = emacs_gtk_hash_magic_event; | |
462 | 1629 gtk_event_stream->add_timeout_cb = emacs_gtk_add_timeout; |
1630 gtk_event_stream->remove_timeout_cb = emacs_gtk_remove_timeout; | |
1631 gtk_event_stream->select_console_cb = emacs_gtk_select_console; | |
1632 gtk_event_stream->unselect_console_cb = emacs_gtk_unselect_console; | |
1633 gtk_event_stream->select_process_cb = emacs_gtk_select_process; | |
1634 gtk_event_stream->unselect_process_cb = emacs_gtk_unselect_process; | |
1204 | 1635 gtk_event_stream->drain_queue_cb = emacs_gtk_drain_queue; |
876 | 1636 gtk_event_stream->create_io_streams_cb= emacs_gtk_create_io_streams; |
1637 gtk_event_stream->delete_io_streams_cb= emacs_gtk_delete_io_streams; | |
1204 | 1638 gtk_event_stream->force_event_pending_cb= emacs_gtk_force_event_pending; |
462 | 1639 |
1640 the_GTK_timeout_blocktype = Blocktype_new (struct GTK_timeout_blocktype); | |
1641 | |
1642 /* this function only makes safe calls */ | |
1643 init_what_input_once (); | |
1644 } | |
1645 | |
1646 void | |
1647 vars_of_event_gtk (void) | |
1648 { | |
1649 DEFVAR_BOOL ("gtk-allow-sendevents", >k_allow_sendevents /* | |
1650 *Non-nil means to allow synthetic events. Nil means they are ignored. | |
1651 Beware: allowing emacs to process SendEvents opens a big security hole. | |
1652 */ ); | |
1653 gtk_allow_sendevents = 0; | |
1654 | |
1655 last_quit_check_signal_tick_count = 0; | |
1656 } | |
1657 | |
1658 void | |
1659 init_event_gtk_late (void) /* called when already initialized */ | |
1660 { | |
1661 timeout_id_tick = 1; | |
1662 pending_timeouts = 0; | |
1663 completed_timeouts = 0; | |
1664 | |
1665 event_stream = gtk_event_stream; | |
1666 | |
1667 #if 0 | |
1668 /* Shut GDK the hell up */ | |
1669 gdk_error_trap_push (); | |
1670 #endif | |
1671 | |
1672 gdk_input_add (signal_event_pipe[0], GDK_INPUT_READ, | |
1673 (GdkInputFunction) gtk_what_callback, NULL); | |
1674 } | |
1675 | |
1676 /* Bogus utility routines */ | |
1416 | 1677 static const char * |
1678 event_name (GdkEvent *ev) | |
462 | 1679 { |
1680 return (gtk_event_name (ev->any.type)); | |
1681 } | |
1682 | |
1683 /* This is down at the bottom of the file so I can avoid polluting the | |
1684 generic code with this X specific CRAP! */ | |
1685 | |
4908
b3ce27ca7647
various fixes related to gtk, redisplay-xlike-inc.c
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1686 #include "sysgdkx.h" |
462 | 1687 #include <X11/keysym.h> |
1688 /* #### BILL!!! Fix this please! */ | |
1689 | |
1690 | |
1691 /************************************************************************/ | |
1692 /* keymap handling */ | |
1693 /************************************************************************/ | |
1694 | |
1695 /* X bogusly doesn't define the interpretations of any bits besides | |
1696 ModControl, ModShift, and ModLock; so the Interclient Communication | |
1697 Conventions Manual says that we have to bend over backwards to figure | |
1698 out what the other modifier bits mean. According to ICCCM: | |
1699 | |
1700 - Any keycode which is assigned ModControl is a "control" key. | |
1701 | |
1702 - Any modifier bit which is assigned to a keycode which generates Meta_L | |
1703 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper, | |
1704 etc. | |
1705 | |
1706 - Any keypress event which contains ModControl in its state should be | |
1707 interpreted as a "control" character. | |
1708 | |
1709 - Any keypress event which contains a modifier bit in its state which is | |
1710 generated by a keycode whose corresponding keysym is Meta_L or Meta_R | |
1711 should be interpreted as a "meta" character. Likewise for Super, Hyper, | |
1712 etc. | |
1713 | |
1714 - It is illegal for a keysym to be associated with more than one modifier | |
1715 bit. | |
1716 | |
1717 This means that the only thing that emacs can reasonably interpret as a | |
1718 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates | |
1719 one of the modifier bits Mod1-Mod5. | |
1720 | |
1721 Unfortunately, many keyboards don't have Meta keys in their default | |
1722 configuration. So, if there are no Meta keys, but there are "Alt" keys, | |
1723 emacs will interpret Alt as Meta. If there are both Meta and Alt keys, | |
1724 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to | |
1725 mean "Symbol," but that just confused the hell out of way too many people). | |
1726 | |
1727 This works with the default configurations of the 19 keyboard-types I've | |
1728 checked. | |
1729 | |
1730 Emacs detects keyboard configurations which violate the above rules, and | |
1731 prints an error message on the standard-error-output. (Perhaps it should | |
1732 use a pop-up-window instead.) | |
1733 */ | |
1734 | |
1735 static void | |
1736 gtk_reset_key_mapping (struct device *d) | |
1737 { | |
1738 Display *display = GDK_DISPLAY (); | |
1739 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1740 KeySym *keysym, *keysym_end; | |
1741 Lisp_Object hashtable; | |
1742 int key_code_count, keysyms_per_code; | |
1743 | |
2054 | 1744 if (xd->x_keysym_map) |
1745 XFree ((char *) xd->x_keysym_map); | |
462 | 1746 XDisplayKeycodes (display, |
1747 &xd->x_keysym_map_min_code, | |
1748 &xd->x_keysym_map_max_code); | |
1749 key_code_count = xd->x_keysym_map_max_code - xd->x_keysym_map_min_code + 1; | |
2054 | 1750 xd->x_keysym_map = |
462 | 1751 XGetKeyboardMapping (display, xd->x_keysym_map_min_code, key_code_count, |
1752 &xd->x_keysym_map_keysyms_per_code); | |
1753 | |
1754 hashtable = xd->x_keysym_map_hashtable; | |
1755 if (HASH_TABLEP (hashtable)) | |
1756 { | |
1757 Fclrhash (hashtable); | |
1758 } | |
1759 else | |
1760 { | |
1761 xd->x_keysym_map_hashtable = hashtable = | |
5191
71ee43b8a74d
Add #'equalp as a hash test by default; add #'define-hash-table-test, GNU API
Aidan Kehoe <kehoea@parhasard.net>
parents:
5178
diff
changeset
|
1762 make_lisp_hash_table (128, HASH_TABLE_NON_WEAK, Qequal); |
462 | 1763 } |
1764 | |
2054 | 1765 for (keysym = xd->x_keysym_map, |
462 | 1766 keysyms_per_code = xd->x_keysym_map_keysyms_per_code, |
1767 keysym_end = keysym + (key_code_count * keysyms_per_code); | |
1768 keysym < keysym_end; | |
1769 keysym += keysyms_per_code) | |
1770 { | |
1771 int j; | |
1772 | |
1773 if (keysym[0] == NoSymbol) | |
1774 continue; | |
1775 | |
1776 { | |
771 | 1777 Extbyte *name = XKeysymToString (keysym[0]); |
462 | 1778 Lisp_Object sym = gtk_keysym_to_emacs_keysym (keysym[0], 0); |
1779 if (name) | |
1780 { | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
1781 Fputhash (build_extstring (name, Qx_keysym_encoding), |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1782 Qsans_modifiers, hashtable); |
462 | 1783 Fputhash (sym, Qsans_modifiers, hashtable); |
1784 } | |
1785 } | |
1786 | |
1787 for (j = 1; j < keysyms_per_code; j++) | |
1788 { | |
1789 if (keysym[j] != keysym[0] && | |
1790 keysym[j] != NoSymbol) | |
1791 { | |
771 | 1792 Extbyte *name = XKeysymToString (keysym[j]); |
462 | 1793 Lisp_Object sym = gtk_keysym_to_emacs_keysym (keysym[j], 0); |
1794 if (name && NILP (Fgethash (sym, hashtable, Qnil))) | |
1795 { | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
1796 Fputhash (build_extstring (name, Qx_keysym_encoding), |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1797 Qt, hashtable); |
462 | 1798 Fputhash (sym, Qt, hashtable); |
1799 } | |
1800 } | |
1801 } | |
1802 } | |
1803 } | |
1804 | |
1805 static const char * | |
1806 index_to_name (int indice) | |
1807 { | |
1808 switch (indice) | |
1809 { | |
1810 case ShiftMapIndex: return "ModShift"; | |
1811 case LockMapIndex: return "ModLock"; | |
1812 case ControlMapIndex: return "ModControl"; | |
1813 case Mod1MapIndex: return "Mod1"; | |
1814 case Mod2MapIndex: return "Mod2"; | |
1815 case Mod3MapIndex: return "Mod3"; | |
1816 case Mod4MapIndex: return "Mod4"; | |
1817 case Mod5MapIndex: return "Mod5"; | |
1818 default: return "???"; | |
1819 } | |
1820 } | |
1821 | |
1822 /* Boy, I really wish C had local functions... */ | |
1823 struct c_doesnt_have_closures /* #### not yet used */ | |
1824 { | |
1825 int warned_about_overlapping_modifiers; | |
1826 int warned_about_predefined_modifiers; | |
1827 int warned_about_duplicate_modifiers; | |
1828 int meta_bit; | |
1829 int hyper_bit; | |
1830 int super_bit; | |
1831 int alt_bit; | |
1832 int mode_bit; | |
1833 }; | |
1834 | |
1835 static void | |
1836 gtk_reset_modifier_mapping (struct device *d) | |
1837 { | |
1838 Display *display = GDK_DISPLAY (); | |
1839 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1840 int modifier_index, modifier_key, column, mkpm; | |
1841 int warned_about_overlapping_modifiers = 0; | |
1842 /* int warned_about_predefined_modifiers = 0; */ | |
1843 /* int warned_about_duplicate_modifiers = 0; */ | |
1844 int meta_bit = 0; | |
1845 int hyper_bit = 0; | |
1846 int super_bit = 0; | |
1847 int alt_bit = 0; | |
1848 int mode_bit = 0; | |
1849 XModifierKeymap *map = (XModifierKeymap *) xd->x_modifier_keymap; | |
1850 | |
1851 xd->lock_interpretation = 0; | |
1852 | |
1853 if (map) | |
3949 | 1854 { |
1855 XFreeModifiermap (xd->x_modifier_keymap); | |
1856 /* Set it to NULL in case we receive two MappingModifier events in a | |
1857 row, and the second is processed during some CHECK_QUITs within | |
1858 x_reset_key_mapping. If that happens, XFreeModifierMap will be | |
1859 called twice on the same map, and we crash. */ | |
1860 xd->x_modifier_keymap = NULL; | |
1861 } | |
462 | 1862 |
1863 gtk_reset_key_mapping (d); | |
1864 | |
1865 xd->x_modifier_keymap = map = XGetModifierMapping (display); | |
1866 | |
1867 /* Boy, I really wish C had local functions... | |
1868 */ | |
1869 | |
1870 #define store_modifier(name,old) \ | |
1871 old = modifier_index; | |
1872 | |
1873 mkpm = map->max_keypermod; | |
1874 for (modifier_index = 0; modifier_index < 8; modifier_index++) | |
1875 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) { | |
1876 KeySym last_sym = 0; | |
1877 for (column = 0; column < 4; column += 2) { | |
1878 KeyCode code = map->modifiermap[modifier_index * mkpm | |
1879 + modifier_key]; | |
1880 KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0); | |
1881 if (sym == last_sym) continue; | |
1882 last_sym = sym; | |
1883 switch (sym) { | |
1884 case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break; | |
1885 case XK_Meta_L: store_modifier ("Meta_L", meta_bit); break; | |
1886 case XK_Meta_R: store_modifier ("Meta_R", meta_bit); break; | |
1887 case XK_Super_L: store_modifier ("Super_L", super_bit); break; | |
1888 case XK_Super_R: store_modifier ("Super_R", super_bit); break; | |
1889 case XK_Hyper_L: store_modifier ("Hyper_L", hyper_bit); break; | |
1890 case XK_Hyper_R: store_modifier ("Hyper_R", hyper_bit); break; | |
1891 case XK_Alt_L: store_modifier ("Alt_L", alt_bit); break; | |
1892 case XK_Alt_R: store_modifier ("Alt_R", alt_bit); break; | |
1893 #if 0 | |
1894 case XK_Control_L: check_modifier ("Control_L", ControlMask); break; | |
1895 case XK_Control_R: check_modifier ("Control_R", ControlMask); break; | |
1896 case XK_Shift_L: check_modifier ("Shift_L", ShiftMask); break; | |
1897 case XK_Shift_R: check_modifier ("Shift_R", ShiftMask); break; | |
1898 #endif | |
1899 case XK_Shift_Lock: /* check_modifier ("Shift_Lock", LockMask); */ | |
1900 xd->lock_interpretation = XK_Shift_Lock; break; | |
1901 case XK_Caps_Lock: /* check_modifier ("Caps_Lock", LockMask); */ | |
1902 xd->lock_interpretation = XK_Caps_Lock; break; | |
1903 | |
1904 /* It probably doesn't make any sense for a modifier bit to be | |
1905 assigned to a key that is not one of the above, but OpenWindows | |
1906 assigns modifier bits to a couple of random function keys for | |
1907 no reason that I can discern, so printing a warning here would | |
1908 be annoying. */ | |
1909 } | |
1910 } | |
1911 } | |
1912 #undef store_modifier | |
1913 #undef check_modifier | |
1914 #undef modwarn | |
1915 #undef modbarf | |
1916 | |
1917 /* If there was no Meta key, then try using the Alt key instead. | |
1918 If there is both a Meta key and an Alt key, then the Alt key | |
1919 is not disturbed and remains an Alt key. */ | |
1920 if (! meta_bit && alt_bit) | |
1921 meta_bit = alt_bit, alt_bit = 0; | |
1922 | |
1923 /* mode_bit overrides everything, since it's processed down inside of | |
1924 XLookupString() instead of by us. If Meta and Mode_switch both | |
1925 generate the same modifier bit (which is an error), then we don't | |
1926 interpret that bit as Meta, because we can't make XLookupString() | |
1927 not interpret it as Mode_switch; and interpreting it as both would | |
1928 be totally wrong. */ | |
1929 if (mode_bit) | |
1930 { | |
1931 const char *warn = 0; | |
1932 if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; | |
1933 else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; | |
1934 else if (mode_bit == super_bit) warn = "Super", super_bit = 0; | |
1935 else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0; | |
1936 if (warn) | |
1937 { | |
1938 warn_when_safe | |
1939 (Qkey_mapping, Qwarning, | |
1940 "XEmacs: %s is being used for both Mode_switch and %s.", | |
1941 index_to_name (mode_bit), warn), | |
1942 warned_about_overlapping_modifiers = 1; | |
1943 } | |
1944 } | |
1945 #undef index_to_name | |
1946 | |
1947 xd->MetaMask = (meta_bit ? (1 << meta_bit) : 0); | |
1948 xd->HyperMask = (hyper_bit ? (1 << hyper_bit) : 0); | |
1949 xd->SuperMask = (super_bit ? (1 << super_bit) : 0); | |
1950 xd->AltMask = (alt_bit ? (1 << alt_bit) : 0); | |
1951 xd->ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */ | |
1952 | |
1953 } | |
1954 | |
1955 void | |
1956 gtk_init_modifier_mapping (struct device *d) | |
1957 { | |
1958 struct gtk_device *gd = DEVICE_GTK_DATA (d); | |
1959 gd->x_keysym_map_hashtable = Qnil; | |
1960 gd->x_keysym_map = NULL; | |
1961 gd->x_modifier_keymap = NULL; | |
1962 gtk_reset_modifier_mapping (d); | |
1963 } | |
1964 | |
1965 #if 0 | |
1966 static int | |
1967 gtk_key_is_modifier_p (KeyCode keycode, struct device *d) | |
1968 { | |
1969 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1970 KeySym *syms; | |
1971 KeySym *map = (KeySym *) xd->x_keysym_map; | |
1972 int i; | |
1973 | |
1974 if (keycode < xd->x_keysym_map_min_code || | |
1975 keycode > xd->x_keysym_map_max_code) | |
1976 return 0; | |
1977 | |
1978 syms = &map [(keycode - xd->x_keysym_map_min_code) * | |
1979 xd->x_keysym_map_keysyms_per_code]; | |
1980 for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) | |
1981 if (IsModifierKey (syms [i]) || | |
1982 syms [i] == XK_Mode_switch) /* why doesn't IsModifierKey count this? */ | |
1983 return 1; | |
1984 return 0; | |
1985 } | |
1986 #endif |