Mercurial > hg > xemacs-beta
view src/ExternalClient.c @ 593:5fd7ba8b56e7
[xemacs-hg @ 2001-05-31 12:45:27 by ben]
xemacs-faq.texi: Major rewrite.
Update all MS Windows info to current.
Redo section 6.1 almost completely.
Incorporate sections 1 and 2 of Hrvoje's FAQ.
etags.el: Fix infloop when going up to the root.
s\cygwin32.h: Don't unilaterally include ntplay, but only when we're compiling
with native sound (look in configure now).
event-msw.c: Fix yet more problems with C-g handling.
Implement debug-mswindows-events.
event-stream.c, events.h, signal.c, sysdep.h:
Rearrange the signal-handling code to eliminate the former
spaghetti logic paths in it. Document clearly what
"low-level" and "high-level" timeouts are. Rename some
functions with unclear names (e.g. "...alarm...") to names
that reflect what they actually do (e.g. "...async_timeout...").
Fix numerous bugs discovered in the process.
console-x.h, event-Xt.c, event-msw.c, frame-x.c:
Hopefully make XEmacs properly maintain the "iconified"
state on frames at all times. This should fix the "can't
delete a frame with C-x 5 0 when there's another iconified
frame out there" bug.
Put a notice in of further changes that should probably
be made to clean up the frame-visibility support.
(especially directed at Jan Vroonhof)
lisp.h, miscplay.c:
Rename SBufbyte to CBufbyte to avoid a misleading name.
Eliminate UChar, which is not used anywhere and contributes
no semantic info. Add a comment about the documentation-only
properties of the char/unsigned char typedefs. Add
SChar_Binary as an explicitly `signed' version of Char_Binary
and put back the `signed' declarations in miscplay.c.
alloc.c:
Use char typedefs.
console-msw.c, device-msw.c, dialog-msw.c, editfns.c, fileio.c, glyphs-eimage.c, menubar-msw.c, ntplay.c, objects-msw.c, realpath.c, redisplay-msw.c, select-msw.c, syswindows.h, win32.c:
Eliminate numerous C++ errors.
frame-msw.c:
Eliminate numerous C++ errors and Mule-ize.
glyphs-msw.c:
Eliminate numerous C++ errors and use char typedefs.
configure.in:
Fix problems detecting both native and Linux sound on Cygwin
when compiled with --with-msw=no.
Rearrange file-coding handling a bit to avoid warning when
compiling with Mule.
configure.in, configure.usage, INSTALL:
Document XEMACS_CC and corresponding compiler option --xemacs-compiler.
Explain how to build xemacs using a C++ compiler.
| author | ben |
|---|---|
| date | Thu, 31 May 2001 12:45:41 +0000 |
| parents | abe6d1db359e |
| children | 4f4c898836ab |
line wrap: on
line source
/* External client widget. Copyright (C) 1993, 1994 Sun Microsystems, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Synched up with: Not in FSF. */ /* Written by Ben Wing, September 1993. */ #ifdef emacs #include <config.h> #ifndef EXTERNAL_WIDGET ERROR! This ought not be getting compiled if EXTERNAL_WIDGET is undefined #endif #endif /* emacs */ #include <stdio.h> #include <string.h> #include <stdlib.h> #ifdef EXTW_USES_MOTIF # include <Xm/XmP.h> # include <Xm/PrimitiveP.h> # include <X11/keysym.h> #else # include "xintrinsicp.h" # include <X11/StringDefs.h> #endif #include "ExternalClientP.h" #include "extw-Xt.h" #ifdef TOOLTALK #include TT_C_H_FILE #endif /* This is the client widget, used to communicate with an ExternalShell widget. */ #define NOTIFY(w, type, l0, l1, l2) \ extw_send_notify_3(XtDisplay((Widget)(w)), XtWindow((Widget)(w)),\ type, l0, l1, l2) static void externalClientInitialize (Widget req, Widget new, ArgList args, Cardinal *num_args); static void externalClientRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs); static void Destroy (Widget w); static void EventHandler (Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch); static void MaskableEventHandler (Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch); static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *, XtWidgetGeometry *); static void ExternalClientFocusIn (Widget, XEvent *, String *, Cardinal *); static void ExternalClientFocusOut (Widget, XEvent *, String *, Cardinal *); static void ExternalClientEnter (Widget, XEvent *, String *, Cardinal *); static void ExternalClientLeave (Widget, XEvent *, String *, Cardinal *); static int my_error_handler(Display *display, XErrorEvent *xev); static int (*error_old_handler)(Display *, XErrorEvent *); static XtResource resources[] = { #define offset(field) XtOffset(ExternalClientWidget, externalClient.field) { XtNshellTimeout, XtCShellTimeout, XtRInt, sizeof (int), offset(shell_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT }, { XtNdeadShell, XtCDeadShell, XtRBoolean, sizeof (Boolean), offset(dead_shell), XtRImmediate, (XtPointer)False }, #ifdef EXTW_USES_MOTIF { XmNnavigationType, XmCNavigationType, XmRNavigationType, sizeof (XmNavigationType), XtOffset (ExternalClientWidget, primitive.navigation_type), XtRImmediate, (XtPointer)XmTAB_GROUP }, #endif { XtNemacsProcID, XtCEmacsProcID, XtRString, sizeof (String), offset(emacs_procid), XtRImmediate, (XtPointer)NULL }, { XtNshellReadyCallback, XtCCallback, XtRCallback, sizeof (XtCallbackList), offset(shell_ready_callback), XtRImmediate, (XtPointer)NULL }, { XtNshellName, XtCShellName, XtRString, sizeof (String), offset(shell_name), XtRImmediate, (XtPointer)NULL }, { XtNuseToolTalk, XtCUseToolTalk, XtRBoolean, sizeof (Boolean), offset(use_tooltalk), XtRImmediate, (XtPointer)False } }; static XtActionsRec actions[] = { {"focusIn", ExternalClientFocusIn}, {"focusOut", ExternalClientFocusOut}, {"enter", ExternalClientEnter}, {"leave", ExternalClientLeave}, }; ExternalClientClassRec externalClientClassRec = { { /* * core_class fields */ #ifdef EXTW_USES_MOTIF /* superclass */ (WidgetClass) &xmPrimitiveClassRec, #else /* superclass */ (WidgetClass) &coreClassRec, #endif /* class_name */ "ExternalClient", /* size */ sizeof (ExternalClientRec), /* Class Initializer */ NULL, /* class_part_initialize*/ NULL, /* XtInheritClassPartInitialize, */ /* Class init'ed ? */ FALSE, /* initialize */ externalClientInitialize, /* initialize_notify */ NULL, /* realize */ externalClientRealize, /* actions */ actions, /* num_actions */ XtNumber (actions), /* resources */ resources, /* resource_count */ XtNumber (resources), /* xrm_class */ NULLQUARK, /* compress_motion */ FALSE, /* compress_exposure */ TRUE, /* compress_enterleave*/ FALSE, /* visible_interest */ TRUE, /* destroy */ Destroy, /* XtInheritDestroy, */ /* resize */ XtInheritResize, /* expose */ NULL, /* set_values */ NULL, /* XtInheritSetValues, */ /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* intrinsics version */ XtVersion, /* callback offsets */ NULL, /* tm_table */ "", /* MUST NOT BE NULL or XtInheritTranslations in Motif!!!!! Otherwise keyboard focus translations will not work. */ /* query_geometry */ QueryGeometry, /* display_accelerator*/ NULL, /* extension */ NULL }, #ifdef EXTW_USES_MOTIF { XmInheritBorderHighlight,/* Primitive border_highlight */ XmInheritBorderHighlight,/* Primitive border_unhighlight */ XtInheritTranslations, /* translations */ NULL, /* arm_and_activate */ NULL, /* get resources */ 0, /* num get_resources */ NULL, /* extension */ }, #endif { 0 } }; WidgetClass externalClientWidgetClass = (WidgetClass) &externalClientClassRec; static void externalClientInitialize (Widget req, Widget new, ArgList args, Cardinal *num_args) { ExternalClientWidget ecw = (ExternalClientWidget) new; static int error_handler_added = 0; extw_initialize_atoms (XtDisplay (new)); extw_which_side = extw_client_send; #ifdef EXTW_USES_MOTIF /* yes I know this is horrible. However, the XmPrimitive class adds the Tab translation in its initialization routine, so we have to override it here. This is all the fault of Xt, which doesn't provide a proper inheritance mechanism for translations. -- BPW */ XtOverrideTranslations (new, XtParseTranslationTable ("None<Key>Tab:\n" "<FocusIn>:focusIn()\n" "<FocusOut>:focusOut()\n" "<Enter>:enter()\n" "<Leave>:leave()\n")); #endif XtAddEventHandler (new, 0, TRUE, EventHandler, (XtPointer) NULL); ecw->externalClient.shell_ready = False; ecw->externalClient.has_focus = False; if (!error_handler_added) { error_handler_added = 1; error_old_handler = XSetErrorHandler (my_error_handler); } } #ifdef TOOLTALK static Tt_callback_action tt_callback(Tt_message m, Tt_pattern p) { ExternalClientWidget ecw = (ExternalClientWidget)tt_message_user (m, 0); switch (tt_message_state(m)) { case TT_FAILED: /* handle errors here */ break; case TT_HANDLED: ecw->externalClient.shell_name = tt_message_arg_val (m, 2); XtCallCallbackList ((Widget) ecw, ecw->externalClient.shell_ready_callback, NULL); break; } tt_message_destroy (m); return TT_CALLBACK_PROCESSED; } static void send_tooltalk_handshake (ExternalClientWidget ecw, Window win, char *name) { Tt_message m = tt_message_create (); tt_message_op_set (m, "emacs-make-client-screen"); tt_message_scope_set (m, TT_SESSION); tt_message_class_set (m, TT_REQUEST); tt_message_arg_add (m, TT_IN, "string", name); tt_message_iarg_add (m, TT_IN, "int", win); tt_message_arg_add (m, TT_OUT, "string", NULL); tt_message_user_set (m, 0, (void *)ecw); tt_message_callback_add (m, tt_callback); if (ecw->externalClient.emacs_procid) { tt_message_address_set (m, TT_HANDLER); tt_message_handler_set (m, ecw->externalClient.emacs_procid); } else tt_message_address_set (m, TT_PROCEDURE); tt_message_send (m); } #endif static void externalClientRealize (Widget w, XtValueMask *vm, XSetWindowAttributes *attrs) { ExternalClientWidget ecw = (ExternalClientWidget)w; #ifdef EXTW_USES_MOTIF (*xmPrimitiveWidgetClass->core_class.realize) (w, vm, attrs); #else (*coreWidgetClass->core_class.realize) (w, vm, attrs); #endif #ifdef TOOLTALK /* Make sure that the server actually knows about this window id before * telling Emacs about it. */ if (ecw->externalClient.use_tooltalk) { XSync (XtDisplay (w), False); send_tooltalk_handshake (ecw, XtWindow (w), XtName (w)); } #endif } /***********************************************************************/ /* window-to-widget list. */ struct ww_list { Window win; Widget wid; struct ww_list *next; }; struct ww_list ww_list[1]; static int add_ww (Window win, Widget wid) { struct ww_list *ww = (struct ww_list *) malloc (sizeof (struct ww_list)); if (!ww) return 0; ww->win = win; ww->wid = wid; ww->next = ww_list->next; ww_list->next = ww; return 1; } static Widget remove_ww (Window win) { struct ww_list *w1, *w2; Widget wid = 0; for (w1=ww_list, w2=w1->next; w2; w1=w2, w2=w2->next) if (w2->win == win) { w1->next = w2->next; wid = w2->wid; free (w2); break; } return wid; } /***********************************************************************/ /* stolen outright from Intrinsic.c */ static void ComputeWindowAttributes(widget,value_mask,values) Widget widget; XtValueMask *value_mask; XSetWindowAttributes *values; { *value_mask = CWEventMask | CWColormap; (*values).event_mask = XtBuildEventMask(widget); (*values).colormap = widget->core.colormap; if (widget->core.background_pixmap != XtUnspecifiedPixmap) { *value_mask |= CWBackPixmap; (*values).background_pixmap = widget->core.background_pixmap; } else { *value_mask |= CWBackPixel; (*values).background_pixel = widget->core.background_pixel; } if (widget->core.border_pixmap != XtUnspecifiedPixmap) { *value_mask |= CWBorderPixmap; (*values).border_pixmap = widget->core.border_pixmap; } else { *value_mask |= CWBorderPixel; (*values).border_pixel = widget->core.border_pixel; } if (widget->core.widget_class->core_class.expose == (XtExposeProc) NULL) { /* Try to avoid redisplay upon resize by making bit_gravity the same as the default win_gravity */ *value_mask |= CWBitGravity; (*values).bit_gravity = NorthWestGravity; } } /* ComputeWindowAttributes */ static void end_connection (ExternalClientWidget w) { XSetWindowAttributes xswa; XtValueMask mask; Widget wid = (Widget) w; w->externalClient.shell_ready = False; XtRemoveEventHandler (wid, w->externalClient.event_mask, FALSE, MaskableEventHandler, (XtPointer) NULL); ComputeWindowAttributes (wid, &mask, &xswa); XChangeWindowAttributes (XtDisplay (wid), XtWindow (wid), mask, &xswa); XClearArea (XtDisplay (wid), XtWindow (wid), 0, 0, 0, 0, True); } static int my_error_handler (Display *display, XErrorEvent *xev) { Widget wid; if (xev->error_code != BadWindow) goto call_old; wid = remove_ww (xev->resourceid); if (wid) { end_connection ((ExternalClientWidget) wid); return 0; } call_old: return error_old_handler (display, xev); } static void MaskableEventHandler (Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch) /* closure and continue_to_dispatch unused */ { ExternalClientWidget w = (ExternalClientWidget) wid; if (w->externalClient.shell_ready) { if (event->type == KeyPress || event->type == KeyRelease || event->type == ButtonPress || event->type == ButtonRelease || event->type == MotionNotify) event->xkey.subwindow = 0; #ifdef EXTW_USES_MOTIF /* hackkkkkkkkkkkkkk! Suppress CTRL-TAB, SHIFT-TAB, etc. so that Emacs doesn't attempt to interpret focus-change keystrokes. */ if (event->type == KeyPress && XLookupKeysym ((XKeyEvent *) event, 0) == XK_Tab && (event->xkey.state & ControlMask || event->xkey.state & ShiftMask)) return; #endif event->xany.window = w->core.window; XSendEvent (XtDisplay (wid), w->externalClient.event_window, FALSE, 0, event); XSync (XtDisplay (wid), 0); /* make sure that any BadWindow errors (meaning the server died) get handled before XSendEvent is called again. */ } } static void EventHandler (Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch) /* closure and continue_to_dispatch unused */ { ExternalClientWidget w = (ExternalClientWidget) wid; if (w->core.window != event->xany.window) { XtAppErrorMsg (XtWidgetToApplicationContext (wid), "invalidWindow","eventHandler",XtCXtToolkitError, "Event with wrong window", (String *)NULL, (Cardinal *)NULL); return; } if (event->type == ClientMessage && event->xclient.message_type == a_EXTW_NOTIFY && event->xclient.data.l[0] == extw_shell_send) switch (event->xclient.data.l[1]) { case extw_notify_qg: /* shell is alive again. */ w->externalClient.dead_shell = False; break; case extw_notify_gm: { XtWidgetGeometry xwg, xwg_return; XtGeometryResult result; extw_get_geometry_value (XtDisplay (wid), XtWindow (wid), a_EXTW_GEOMETRY_MANAGER, &xwg); result = XtMakeGeometryRequest (wid, &xwg, &xwg_return); extw_send_geometry_value (XtDisplay (wid), XtWindow (wid), a_EXTW_GEOMETRY_MANAGER, extw_notify_gm, result == XtGeometryAlmost ? &xwg_return : NULL, result); break; } case extw_notify_init: w->externalClient.shell_ready = True; w->externalClient.event_window = event->xclient.data.l[2]; w->externalClient.event_mask = event->xclient.data.l[3]; add_ww (w->externalClient.event_window, (Widget) w); XtAddEventHandler (wid, w->externalClient.event_mask, FALSE, MaskableEventHandler, (XtPointer) NULL); #ifdef EXTW_USES_MOTIF NOTIFY (w, extw_notify_init, EXTW_TYPE_MOTIF, 0, 0); #else NOTIFY (w, extw_notify_init, EXTW_TYPE_XT, 0, 0); #endif break; case extw_notify_end: end_connection (w); remove_ww (w->externalClient.event_window); break; case extw_notify_set_focus: #ifdef EXTW_USES_MOTIF XmProcessTraversal (wid, XmTRAVERSE_CURRENT); #else XtSetKeyboardFocus (wid, None); #endif break; } } static void Destroy(wid) Widget wid; { ExternalClientWidget w = (ExternalClientWidget)wid; NOTIFY(w, extw_notify_end, 0, 0, 0); } static XtGeometryResult QueryGeometry(gw, request, reply) Widget gw; XtWidgetGeometry *request, *reply; { ExternalClientWidget w = (ExternalClientWidget)gw; XEvent event; unsigned long request_num; Display *display = XtDisplay(gw); XtWidgetGeometry req = *request; /* don't modify caller's structure */ if (!XtIsRealized((Widget)w) || !w->externalClient.shell_ready) return XtGeometryYes; if (w->externalClient.dead_shell == TRUE) /* The shell is sick. */ return XtGeometryNo; req.sibling = None; req.request_mode &= ~CWSibling; request_num = NextRequest(display); extw_send_geometry_value(XtDisplay(gw), XtWindow(gw), a_EXTW_QUERY_GEOMETRY, extw_notify_qg, &req, 0); if (extw_wait_for_response(gw, &event, request_num, extw_notify_qg, w->externalClient.shell_timeout)) { XtGeometryResult result = (XtGeometryResult) event.xclient.data.l[0]; if (result == XtGeometryAlmost) { extw_get_geometry_value(XtDisplay(gw), XtWindow(gw), a_EXTW_QUERY_GEOMETRY, reply); } return result; } else { w->externalClient.dead_shell = TRUE; /* timed out; must be broken */ return XtGeometryNo; } } static void ExternalClientFocusIn (Widget w, XEvent *event, String *params, Cardinal *num_params) { ExternalClientWidget ecw = (ExternalClientWidget) w; if (event->xfocus.send_event && !ecw->externalClient.has_focus) { ecw->externalClient.has_focus = True; NOTIFY(ecw, extw_notify_focus_in, 0, 0, 0); } #ifdef EXTW_USES_MOTIF _XmPrimitiveFocusIn (w, event, params, num_params); #endif } static void ExternalClientFocusOut (Widget w, XEvent *event, String *params, Cardinal *num_params) { ExternalClientWidget ecw = (ExternalClientWidget) w; if (event->xfocus.send_event && ecw->externalClient.has_focus) { ecw->externalClient.has_focus = False; NOTIFY(ecw, extw_notify_focus_out, 0, 0, 0); } #ifdef EXTW_USES_MOTIF _XmPrimitiveFocusOut(w, event, params, num_params); #endif } static void ExternalClientEnter (Widget w, XEvent *event, String *params, Cardinal *num_params) { ExternalClientWidget ecw = (ExternalClientWidget) w; if ( #ifdef EXTW_USES_MOTIF _XmGetFocusPolicy (w) != XmEXPLICIT && #endif !ecw->externalClient.has_focus && event->xcrossing.focus && event->xcrossing.detail != NotifyInferior) { ecw->externalClient.has_focus = True; NOTIFY(ecw, extw_notify_focus_in, 0, 0, 0); } #ifdef EXTW_USES_MOTIF _XmPrimitiveEnter (w, event, params, num_params); #endif } static void ExternalClientLeave (Widget w, XEvent *event, String *params, Cardinal *num_params) { ExternalClientWidget ecw = (ExternalClientWidget) w; if ( #ifdef EXTW_USES_MOTIF _XmGetFocusPolicy (w) != XmEXPLICIT && #endif ecw->externalClient.has_focus && event->xcrossing.focus && event->xcrossing.detail != NotifyInferior) { ecw->externalClient.has_focus = False; NOTIFY(ecw, extw_notify_focus_out, 0, 0, 0); } #ifdef EXTW_USES_MOTIF _XmPrimitiveLeave (w, event, params, num_params); #endif }
