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