home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / lay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  162.2 KB  |  5,723 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    layout.c --- UI routines called by the layout module.
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 23-Jun-94.
  21.  */
  22.  
  23.  
  24. #include "mozilla.h"
  25. #include "xfe.h"
  26. #include "selection.h"
  27. #include "fonts.h"
  28. #include "felocale.h"
  29. #include "fe_proto.h"
  30. #include "msgcom.h"
  31. #include "mozjava.h"
  32. #include "np.h"
  33. #include "nppriv.h"
  34. #include "layout.h"
  35. #include "Xfe/Xfe.h"
  36.  
  37. #include <X11/keysym.h>
  38.  
  39. extern Widget applet_storage;
  40.  
  41. extern PRLogModuleInfo* NSJAVA;
  42. #define warn    PR_LOG_WARN
  43.  
  44. #include <Xm/SashP.h> /* for grid edges */
  45. #include <Xm/DrawP.h> /* #### for _XmDrawShadows() */
  46.  
  47. #include "il_icons.h"           /* Image icon enumeration. */
  48.  
  49. #include "layers.h"
  50.  
  51. #include <plevent.h>
  52. #include <prtypes.h>
  53. #include "libevent.h"
  54.  
  55. #include <libi18n.h>
  56. #include "intl_csi.h"
  57. /* for XP_GetString() */
  58. #include <xpgetstr.h>
  59.  
  60. #ifndef NO_WEB_FONTS
  61. #include "nf.h"
  62. #include "Mnfrc.h"
  63. #include "Mnfrf.h"
  64. #include "Mnffbu.h"
  65. #endif
  66.  
  67. #ifndef MAX
  68. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  69. #endif
  70.  
  71. #if defined(DEBUG_tao)
  72. #define XDBG(x) x
  73. #else
  74. #define XDBG(x) 
  75. #endif
  76.  
  77. extern int XFE_UNTITLED;
  78. extern int XFE_COMPOSE;
  79. extern int XFE_NO_SUBJECT;
  80. extern int XFE_MAIL_TITLE_FMT, XFE_NEWS_TITLE_FMT, XFE_TITLE_FMT;
  81. extern int XFE_EDITOR_TITLE_FMT;
  82. extern int XFE_LAY_UNKNOWN_PARAMETER_TO_ACTIVATE_LINK_ACTION;
  83. extern int XFE_LAY_TOO_MANY_ARGS_TO_ACTIVATE_LINK_ACTION;
  84. extern int XFE_LAY_LOCAL_FILE_URL_UNTITLED;
  85.  
  86. extern MWContext * XFE_showBrowser(Widget toplevel, URL_Struct *url);
  87. extern void fe_HTMLViewTooltipsEH(MWContext *context, CL_Layer *layer,
  88.                                   CL_Event *layer_event, int state);
  89.  
  90. static void fe_get_url_x_selection_cb(Widget w,XtPointer client_data,
  91.                                     Atom * sel,Atom * type,XtPointer value, 
  92.                                     unsigned long * len,int * format);
  93.  
  94. void XFE_ClearView (MWContext *context, int which);
  95.  
  96. void fe_ClearArea (MWContext *context, int x, int y, unsigned int w,
  97.                    unsigned int h);
  98. void fe_ClearAreaWithColor (MWContext *context, int x, int y, unsigned int w,
  99.                             unsigned int h, Pixel color);
  100.  
  101. /* State for the highlighted item (this should eventually be done by
  102.    layout I think).  This is kind of a kludge, but it only assumes that: 
  103.    there is only one mouse; and that the events and translations are 
  104.    being dispatched correctly... */
  105. static LO_Element *last_armed_xref = 0;
  106. static struct {
  107.   MWContext* context;
  108. #ifdef LAYERS_FULL_FE_EVENT
  109.   XEvent xevent;
  110. #else
  111.   fe_EventStruct fe_event;
  112. #endif
  113. } last_armed_xref_closure_for_disarm;
  114. static Boolean last_armed_xref_highlighted_p = False;
  115. MWContext *last_documented_xref_context = 0;
  116. LO_Element *last_documented_xref = 0;
  117. LO_AnchorData *last_documented_anchor_data = 0;
  118.  
  119. int xfeKeycodeToWhich(KeyCode keycode,
  120.               Modifiers modifiers)
  121. {
  122.   Modifiers modout;
  123.   KeySym res;
  124.   XtTranslateKeycode(fe_display,
  125.              keycode, modifiers,
  126.              &modout,&res);
  127.   return res;
  128. }
  129.  
  130. /* takes the state field from a {Button,Key}{Press,Release} event and
  131.  *  maps it into JS event flags.
  132.  */
  133. int xfeToLayerModifiers(int state)
  134. {
  135.   return (  ((state & ShiftMask) ? EVENT_SHIFT_MASK : 0)
  136.       | ((state & ControlMask) ? EVENT_CONTROL_MASK : 0)
  137.       | ((state & Mod1Mask) ? EVENT_ALT_MASK : 0)
  138.       | ((state & (  Mod2Mask
  139.                | Mod3Mask
  140.                | Mod4Mask
  141.                | Mod5Mask
  142.                )) ? EVENT_META_MASK : 0)
  143.       );
  144. }
  145.  
  146. /* This is in the set of function pointers, but there is no
  147.    definition for it. */
  148. MWContext*
  149. XFE_CreateNewDocWindow(MWContext * calling_context,URL_Struct * URL)
  150. {
  151.     if (calling_context) 
  152.     {
  153.         Widget widget = CONTEXT_WIDGET (calling_context);
  154.         
  155.         if (widget)
  156.         {
  157.             Widget app_shell = XfeAncestorFindApplicationShell(widget);
  158.  
  159.             if (XfeIsAlive(app_shell))
  160.             {
  161.                 return XFE_showBrowser(app_shell,URL);
  162.             }
  163.         }
  164.     }/* if */
  165.  
  166.     return NULL;
  167. }
  168.  
  169. /* Translate the string from ISO-8859/1 to something that the window
  170.    system can use (for X, this is nearly a no-op.)
  171.  */
  172. char *
  173. XFE_TranslateISOText (MWContext *context, int charset, char *ISO_Text)
  174. {
  175.   unsigned char *s;
  176.  
  177.   /* charsets such as Shift-JIS contain 0240's that are valid */
  178.   if (INTL_CharSetType(charset) != SINGLEBYTE)
  179.     return ISO_Text;
  180.  
  181.   /* When   is encountered, display a normal space character instead.
  182.      This is necessary because the MIT fonts are messed up, and have a
  183.      zero-width character for nobreakspace, so we need to print it as a
  184.      normal space instead. */
  185.   if (ISO_Text)
  186.     for (s = (unsigned char *) ISO_Text; *s; s++)
  187.       if (*s == 0240) *s = ' ';
  188.  
  189.   return ISO_Text;
  190. }
  191.  
  192. struct fe_gc_data
  193. {
  194.   unsigned long flags;
  195.   XGCValues gcv;
  196.   Region clip_region;
  197.   GC gc;
  198. };
  199.  
  200. /* The GC cache is shared among all windows, since it doesn't hog
  201.    any scarce resources (like colormap entries.) */
  202. static struct fe_gc_data fe_gc_cache [30] = { { 0, }, };
  203. static int fe_gc_cache_fp;
  204. static int fe_gc_cache_wrapped_p = 0;
  205.  
  206. /* Dispose of entries matching the given flags, compressing the GC cache */
  207. void
  208. fe_FlushGCCache (Widget widget, unsigned long flags)
  209. {
  210.   int i, new_fp;
  211.  
  212.   Display *dpy = XtDisplay (widget);
  213.   int maxi = (fe_gc_cache_wrapped_p ? countof (fe_gc_cache) : fe_gc_cache_fp);
  214.   new_fp = 0;
  215.   for (i = 0; i < maxi; i++)
  216.     {
  217.       if (fe_gc_cache [i].flags & flags)
  218.         {
  219.           XFreeGC (dpy, fe_gc_cache [i].gc);
  220.           if (fe_gc_cache [i].clip_region)
  221.               FE_DestroyRegion(fe_gc_cache [i].clip_region);
  222.           memset (&fe_gc_cache [i], 0,  sizeof (fe_gc_cache [i]));
  223.         }
  224.       else
  225.         fe_gc_cache[new_fp++] = fe_gc_cache[i];
  226.     }
  227.   if (new_fp == countof (fe_gc_cache))
  228.     {
  229.       fe_gc_cache_wrapped_p = 1;
  230.       fe_gc_cache_fp = 0;
  231.     }
  232.   else
  233.     {
  234.       fe_gc_cache_wrapped_p = 0;
  235.       fe_gc_cache_fp = new_fp;
  236.     }
  237. }
  238.  
  239. GC
  240. fe_GetGCfromDW(Display* dpy, Window win, unsigned long flags, XGCValues *gcv,
  241.                Region clip_region)
  242. {
  243.   int i;
  244.   for (i = 0;
  245.        i < (fe_gc_cache_wrapped_p ? countof (fe_gc_cache) : fe_gc_cache_fp);
  246.        i++)
  247.       {
  248.           if (flags == fe_gc_cache [i].flags &&
  249.               !memcmp (gcv, &fe_gc_cache [i].gcv, sizeof (*gcv)))
  250.               if (clip_region)
  251.                   {
  252.                       if (fe_gc_cache[i].clip_region &&
  253.                           XEqualRegion(clip_region,
  254.                                        fe_gc_cache[i].clip_region))
  255.                           return fe_gc_cache [i].gc;
  256.                   }
  257.               else
  258.                   {
  259.                       if(!fe_gc_cache[i].clip_region)
  260.                           return fe_gc_cache [i].gc;
  261.                   }
  262.       }
  263.  
  264.   {
  265.     GC gc;
  266.     int this_slot = fe_gc_cache_fp;
  267.     int clear_p = fe_gc_cache_wrapped_p;
  268.  
  269.     fe_gc_cache_fp++;
  270.     if (fe_gc_cache_fp >= countof (fe_gc_cache))
  271.       {
  272.     fe_gc_cache_fp = 0;
  273.     fe_gc_cache_wrapped_p = 1;
  274.       }
  275.  
  276.     if (clear_p)
  277.       {
  278.           XFreeGC (dpy, fe_gc_cache [this_slot].gc);
  279.           if (fe_gc_cache [this_slot].clip_region)
  280.               FE_DestroyRegion(fe_gc_cache [this_slot].clip_region);
  281.           fe_gc_cache [this_slot].gc = NULL;
  282.           fe_gc_cache [this_slot].clip_region = NULL;
  283.       }
  284.  
  285.     gc = XCreateGC (dpy, win, flags, gcv);
  286.  
  287.     fe_gc_cache [this_slot].flags = flags;
  288.     fe_gc_cache [this_slot].gcv = *gcv;
  289.     fe_gc_cache [this_slot].clip_region = NULL;
  290.     if (clip_region) {
  291.         fe_gc_cache [this_slot].clip_region = FE_CopyRegion(clip_region, NULL);
  292.  
  293.         if (fe_gc_cache [this_slot].clip_region) {
  294.             XSetRegion(dpy, gc, fe_gc_cache [this_slot].clip_region);
  295.         }
  296.     }
  297.  
  298.     fe_gc_cache [this_slot].gc = gc;
  299.  
  300.     return gc;
  301.   }
  302. }
  303.  
  304. GC
  305. fe_GetClipGC(Widget widget, unsigned long flags, XGCValues *gcv,
  306.              Region clip_region)
  307. {
  308.     Display *dpy = XtDisplay (widget);
  309.     Window win = XtWindow (widget);
  310.  
  311.     return fe_GetGCfromDW(dpy, win, flags, gcv, clip_region);
  312. }
  313.  
  314. GC
  315. fe_GetGC(Widget widget, unsigned long flags, XGCValues *gcv)
  316. {
  317.     Display *dpy = XtDisplay (widget);
  318.     Window win = XtWindow (widget);
  319.  
  320.     return fe_GetGCfromDW(dpy, win, flags, gcv, NULL);
  321. }
  322.  
  323. static GC
  324. fe_get_text_gc (MWContext *context, LO_TextAttr *text, fe_Font *font_ret,
  325.         Boolean *selected_p, Boolean blunk)
  326. {
  327.   unsigned long flags;
  328.   XGCValues gcv;
  329.   Widget widget = CONTEXT_WIDGET (context);
  330.   fe_Font font = fe_LoadFontFromFace (context, text, &text->charset, text->font_face,
  331.                   text->size, text->fontmask);
  332.   Display *dpy = XtDisplay (widget);
  333.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  334.   Drawable drawable = fe_drawable->xdrawable;
  335.  
  336.   Pixel fg, bg;
  337.   bg = fe_GetPixel(context,
  338.                    text->bg.red, text->bg.green, text->bg.blue);
  339.   fg = fe_GetPixel(context,
  340.                    text->fg.red, text->fg.green, text->fg.blue);
  341.  
  342. /*  if (text->attrmask & LO_ATTR_ANCHOR)
  343.     fg = CONTEXT_DATA (context)->xref_pixel;*/
  344.  
  345.   if (selected_p && *selected_p)
  346.     {
  347.       Pixel nfg = CONTEXT_DATA (context)->select_fg_pixel;
  348.       Pixel nbg = CONTEXT_DATA (context)->select_bg_pixel;
  349.  
  350.       fg = nfg;
  351.       bg = nbg;
  352.     }
  353.  
  354.   if (blunk)
  355.     fg = bg;
  356.  
  357.   if (! font) return NULL;
  358.  
  359.   memset (&gcv, ~0, sizeof (gcv));
  360.  
  361.   flags = 0;
  362.   FE_SET_GC_FONT(text->charset, &gcv, font, &flags);
  363.   gcv.foreground = fg;
  364.   gcv.background = bg;
  365.   flags |= (GCForeground | GCBackground);
  366.  
  367.   if (font_ret) *font_ret = font;
  368.  
  369.   return fe_GetGCfromDW (dpy, drawable,
  370.                          flags, &gcv, fe_drawable->clip_region);
  371. }
  372.  
  373. /* Given text and attributes, returns the size of those characters.
  374.  */
  375. int
  376. XFE_GetTextInfo (MWContext *context,
  377.         LO_TextStruct *text,
  378.         LO_TextInfo *text_info)
  379. {
  380.   fe_Font font;
  381.   char *str = (char *) text->text;
  382.   int length = text->text_len;
  383.   int remaining = length;
  384.  
  385.   font = fe_LoadFontFromFace (context, text->text_attr,
  386.                   &text->text_attr->charset,
  387.                   text->text_attr->font_face,
  388.                   text->text_attr->size,
  389.                   text->text_attr->fontmask);
  390.   /* X is such a winner, it uses 16 bit quantities to represent all pixel
  391.      widths.  This is really swell, because it means that if you've got
  392.      a large font, you can't correctly compute the size of strings which
  393.      are only a few thousand characters long.  So, when the string is more
  394.      than N characters long, we divide up our calls to XTextExtents to
  395.      keep the size down so that the library doesn't run out of fingers
  396.      and toes.
  397.    */
  398. #define SUCKY_X_MAX_LENGTH 600
  399.  
  400.   text_info->ascent = 14;
  401.   text_info->descent = 3;
  402.   text_info->max_width = 0;
  403.   text_info->lbearing = 0;
  404.   text_info->rbearing = 0;
  405.   if (! font) return 0;
  406.  
  407.   do
  408.     {
  409.       int L = (remaining > SUCKY_X_MAX_LENGTH ? SUCKY_X_MAX_LENGTH :
  410.            remaining);
  411.       int ascent, descent;
  412.       XCharStruct overall;
  413.       FE_TEXT_EXTENTS (text->text_attr->charset, font, str, L,
  414.             &ascent, &descent, &overall);
  415.       /* ascent and descent are per the font, not per this text. */
  416.       text_info->ascent = ascent;
  417.       text_info->descent = descent;
  418.  
  419.       text_info->max_width += overall.width;
  420.  
  421. #define FOO(x,y) if (y > x) x = y
  422.       FOO (text_info->lbearing,   overall.lbearing);
  423.       FOO (text_info->rbearing,   overall.rbearing);
  424.       /*
  425.        * If font metrics were set right, overall.descent should never exceed
  426.        * descent, but since there are broken fonts in the world.
  427.        */
  428.       FOO (text_info->descent,   overall.descent);
  429. #undef FOO
  430.  
  431.       str += L;
  432.       remaining -= L;
  433.     }
  434.   while (remaining > 0);
  435.  
  436.   /* What is the return value expected to be?
  437.      layout/layout.c doesn't seem to use it. */
  438.   return 0;
  439. }
  440.  
  441.  
  442. /* Draws a rectangle with dropshadows on the drawing_area window.
  443.    shadow_width is the border thickness (they go inside the rect).
  444.    shadow_style is XmSHADOW_IN or XmSHADOW_OUT.
  445.  */
  446. void
  447. fe_DrawSelectedShadows(MWContext *context, fe_Drawable *fe_drawable,
  448.                        int x, int y, int width, int height,
  449.                        int shadow_width, int shadow_style, Boolean selected)
  450. {
  451.   Widget widget = CONTEXT_WIDGET (context);
  452.   Display *dpy = XtDisplay (widget);
  453.   XGCValues gcv1, gcv2;
  454.   GC gc1, gc2;
  455.   unsigned long flags;
  456.   Drawable drawable = fe_drawable->xdrawable;
  457.  
  458.   memset (&gcv1, ~0, sizeof (gcv1));
  459.   memset (&gcv2, ~0, sizeof (gcv2));
  460.  
  461. #ifdef EDITOR
  462.   if (selected)
  463.   {
  464.       flags = GCForeground;
  465.       gcv1.foreground = CONTEXT_DATA(context)->select_bg_pixel;
  466.       gcv2.foreground = CONTEXT_DATA(context)->select_bg_pixel;
  467.       if (shadow_width < 1)
  468.           shadow_width = 1;
  469.   }
  470.   else if (EDT_IS_EDITOR(context) && shadow_width < 1)
  471.   {
  472.       flags = GCForeground;
  473.       gcv1.foreground = CONTEXT_DATA(context)->bg_pixel;
  474.       gcv2.foreground = CONTEXT_DATA(context)->bg_pixel;
  475.       shadow_width = 1;
  476.   }
  477.   else
  478. #endif /* EDITOR */
  479.  
  480.   if (CONTEXT_DATA (context)->backdrop_pixmap ||
  481.       CONTEXT_DATA (context)->bg_pixel !=
  482.       CONTEXT_DATA (context)->default_bg_pixel)
  483.     {
  484.       static Pixmap gray50 = 0;
  485.       if (! gray50)
  486.     {
  487. #      define gray50_width  8
  488. #      define gray50_height 2
  489.       static char gray50_bits[] = { 0x55, 0xAA };
  490.       gray50 =
  491.         XCreateBitmapFromData (XtDisplay (widget),
  492.                    RootWindowOfScreen (XtScreen (widget)),
  493.                    gray50_bits, gray50_width, gray50_height);
  494.     }
  495.       flags = (GCForeground | GCStipple | GCFillStyle |
  496.            GCTileStipXOrigin | GCTileStipYOrigin);
  497.  
  498. #ifdef EDITOR
  499.       if (EDT_IS_EDITOR(context))
  500.       {
  501.           flags |= GCBackground;
  502.           gcv1.background = CONTEXT_DATA(context)->bg_pixel;
  503.           gcv1.fill_style = FillOpaqueStippled;
  504.       }
  505.       else
  506. #endif /* EDITOR */
  507.       gcv1.fill_style = FillStippled;
  508.       gcv1.stipple = gray50;
  509.       gcv1.ts_x_origin = -CONTEXT_DATA (context)->document_x;
  510.       gcv1.ts_y_origin = -CONTEXT_DATA (context)->document_y;
  511.       gcv1.foreground = fe_GetPixel (context, 0xFF, 0xFF, 0xFF);
  512.       gcv2 = gcv1;
  513.       gcv2.foreground = fe_GetPixel (context, 0x00, 0x00, 0x00);
  514.     }
  515.   else
  516.     {
  517.       flags = GCForeground;
  518.       gcv1.foreground = CONTEXT_DATA (context)->top_shadow_pixel;
  519.       gcv2.foreground = CONTEXT_DATA (context)->bottom_shadow_pixel;
  520.     }
  521.  
  522. #ifdef EDITOR_OLD
  523.   /* We don't want this for tables any more; need to test on
  524.    * other elements which use this code to make sure nothing else
  525.    * depends on this behavior.
  526.    */
  527.   if (selected) {
  528.       gcv1.background = CONTEXT_DATA(context)->select_bg_pixel;
  529.       gcv1.line_style = LineDoubleDash;
  530.  
  531.       gcv2.background = CONTEXT_DATA(context)->select_bg_pixel;
  532.       gcv2.line_style = LineDoubleDash;
  533.  
  534.       flags |= GCLineStyle|GCBackground;
  535.   }
  536. #endif /*EDITOR*/
  537.  
  538.   gc1 = fe_GetGCfromDW (fe_display, drawable, flags, &gcv1, fe_drawable->clip_region);
  539.   gc2 = fe_GetGCfromDW (fe_display, drawable, flags, &gcv2, fe_drawable->clip_region);
  540.  
  541.   _XmDrawShadows (dpy, drawable, gc1, gc2, x, y, width, height,
  542.           shadow_width, shadow_style);
  543. }
  544.  
  545. void
  546. fe_DrawShadows (MWContext *context, fe_Drawable *fe_drawable,
  547.         int x, int y, int width, int height,
  548.         int shadow_width, int shadow_style)
  549. {
  550.     fe_DrawSelectedShadows(context, fe_drawable,
  551.                            x, y, width, height,
  552.                            shadow_width, shadow_style, FALSE);
  553.  
  554. }
  555.  
  556.  
  557. /* Put some text on the screen at the given location with the given
  558.    attributes.  (What is iLocation?  It is ignored.)
  559.  */
  560. static void
  561. fe_display_text (MWContext *context, int iLocation, LO_TextStruct *text,
  562.          int32 start, int32 end, Boolean blunk)
  563. {
  564.   Widget shell = CONTEXT_WIDGET (context);
  565.   Widget drawing_area = CONTEXT_DATA (context)->drawing_area;
  566.   Display *dpy = XtDisplay (shell);
  567.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  568.   Drawable drawable = fe_drawable->xdrawable;
  569.   fe_Font font;
  570.   int ascent, descent;
  571.   GC gc;
  572.   long x, y;
  573.   long x_offset = 0;
  574.   Boolean selected_p = False;
  575.  
  576.  
  577.   if ((text->ele_attrmask & LO_ELE_SELECTED) &&
  578.     (start >= text->sel_start) && (end-1 <= text->sel_end))
  579.     selected_p = True;
  580.  
  581.   gc = fe_get_text_gc (context, text->text_attr, &font, &selected_p, blunk);
  582.   if (!gc)
  583.   {
  584.     return;
  585.   }
  586.  
  587.   FE_FONT_EXTENTS(text->text_attr->charset, font, &ascent, &descent);
  588.  
  589.   x = (text->x + text->x_offset
  590.         - CONTEXT_DATA (context)->document_x);
  591.   y = (text->y + text->y_offset + ascent
  592.         - CONTEXT_DATA (context)->document_y);
  593.   x += fe_drawable->x_origin;
  594.   y += fe_drawable->y_origin;
  595.  
  596.   if (text->text_len == 0)
  597.     return;
  598.  
  599.   if (! XtIsRealized (drawing_area))
  600.     return;
  601.  
  602.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  603.       (y > 0 && y > (CONTEXT_DATA (context)->scrolled_height +
  604.     text->y_offset + ascent)) ||
  605.       (x + text->width < 0) ||
  606.       (y + text->line_height < 0))
  607.     return;
  608.  
  609.   if (start < 0)
  610.     start = 0;
  611.   if (end > text->text_len)
  612.     end = text->text_len;
  613.  
  614.   if (end - start > SUCKY_X_MAX_LENGTH)
  615.     /* that's a fine way to make X blow up *real* good! */
  616.     end = start + SUCKY_X_MAX_LENGTH;
  617.  
  618.   /* #### Oh, this doesn't even work, because Bina is
  619.      passing us massively negative (> 16 bit) starting pixel positions.
  620.    */
  621.  
  622.   if (start > 0)
  623.     {
  624.       XCharStruct overall;
  625.       int ascent, descent;
  626.       if (! font) abort ();
  627.       FE_TEXT_EXTENTS (text->text_attr->charset, font, (char *) text->text,
  628.             start, &ascent, &descent, &overall);
  629.       x_offset = overall.width;
  630.       x += x_offset;
  631.     }
  632.  
  633.  
  634.   if (blunk)
  635.     ;    /* No text to draw. */
  636.   else if (!selected_p && text->text_attr->no_background)
  637.     FE_DRAW_STRING (text->text_attr->charset, dpy, drawable, font, gc, x, y,
  638.     ((char *) text->text) + start, end - start);
  639.   else
  640.   {
  641.     GC gc2;
  642.     gc2 = fe_get_text_gc (context, text->text_attr, &font, &selected_p, TRUE);
  643.     if (!gc2)
  644.         gc2 = gc;
  645.  
  646.     FE_DRAW_IMAGE_STRING (text->text_attr->charset, dpy, drawable, font, gc, gc2,
  647.                           x, y, ((char *) text->text)+start, end - start);
  648.   }
  649.  
  650.   /* Anchor text is no longer underlined by the front end.
  651.    * We deliberately do not test for the LO_ATTR_ANCHOR bit in the attr mask.
  652.    */
  653.   if (text->text_attr->attrmask & 
  654.       (LO_ATTR_UNDERLINE | LO_ATTR_SPELL | LO_ATTR_STRIKEOUT)
  655. #if 0
  656.       || (text->height < text->line_height)
  657. #endif
  658.     )
  659.     {
  660.       int upos;
  661.       unsigned int uthick;
  662.       int ul_width;
  663.  
  664.       if (start == 0 && end == text->text_len)
  665.     {
  666.       ul_width = text->width;
  667.     }
  668.       else
  669.     {
  670.       XCharStruct overall;
  671.       int ascent, descent;
  672.       if (! font) abort ();
  673.       FE_TEXT_EXTENTS (text->text_attr->charset, font,
  674.         (char *) text->text+start, end-start, &ascent, &descent,
  675.         &overall);
  676.       ul_width = overall.width;
  677.     }
  678.  
  679. #if 0
  680.       if (text->height < text->line_height)
  681.     {
  682.       /* If the text is shorter than the line, then XDrawImageString()
  683.          won't fill in the whole background - so we need to do that by
  684.          hand. */
  685.       GC gc;
  686.       XGCValues gcv;
  687.       memset (&gcv, ~0, sizeof (gcv));
  688.       gcv.foreground = (text->selected
  689.                 ? CONTEXT_DATA (context)->highlight_bg_pixel
  690.                 : fe_GetPixel (context,
  691.                        text->text_attr->bg.red,
  692.                        text->text_attr->bg.green,
  693.                        text->text_attr->bg.blue));
  694.     }
  695. #endif
  696.  
  697.       if (text->text_attr->attrmask & LO_ATTR_UNDERLINE)
  698.     {
  699.       int lineDescent;
  700.       upos = fe_GetUnderlinePosition(text->text_attr->charset);
  701.       lineDescent = text->line_height - text->y_offset - ascent - 1;
  702.       if (upos > lineDescent)
  703.         upos = lineDescent;
  704.       XDrawLine (dpy, drawable, gc, x, y + upos, x + ul_width, y + upos);
  705.     }
  706.  
  707.       if (text->text_attr->attrmask & LO_ATTR_SPELL)
  708.     {
  709.         int lineDescent;
  710.         GC gc2;
  711.         XGCValues gcv2;
  712.  
  713.         memset (&gcv2, ~0, sizeof (gcv2));
  714.         gcv2.foreground = fe_GetPixel(context, 0xFF, 0x00, 0x00);
  715.  
  716.         gc2 = fe_GetGC (CONTEXT_WIDGET (context), GCForeground, &gcv2);
  717.  
  718.         upos = fe_GetUnderlinePosition(text->text_attr->charset);
  719.         lineDescent = text->line_height - text->y_offset - ascent - 1;
  720.         if (upos > lineDescent)
  721.             upos = lineDescent;
  722.         XDrawLine (dpy, drawable, gc2, x, y + upos, x + ul_width, y + upos);
  723.     }
  724.  
  725.       if (text->text_attr->attrmask & LO_ATTR_STRIKEOUT)
  726.     {
  727.       upos = fe_GetStrikePosition(text->text_attr->charset, font);
  728.       uthick = (ascent / 8);
  729.       if (uthick <= 1)
  730.         XDrawLine (dpy, drawable, gc, x, y + upos, x + ul_width, y + upos);
  731.       else
  732.         XFillRectangle (dpy, drawable, gc, x, y + upos, ul_width, uthick);
  733.     }
  734.     }
  735. }
  736.  
  737. void
  738. XFE_DisplayText (MWContext *context, int iLocation, LO_TextStruct *text,
  739.     XP_Bool need_bg)
  740. {
  741.   fe_display_text (context, iLocation, text, 0, text->text_len, False);
  742. }
  743.  
  744. void
  745. XFE_DisplaySubtext (MWContext *context, int iLocation,
  746.            LO_TextStruct *text, int32 start_pos, int32 end_pos,
  747.            XP_Bool need_bg)
  748. {
  749.   fe_display_text (context, iLocation, text, start_pos, end_pos + 1, False);
  750. }
  751.  
  752. #ifdef EDITOR
  753.  
  754. /*
  755.  *    End of line indicator.
  756.  */
  757. typedef struct fe_bitmap_info
  758. {
  759.     unsigned char* bits;
  760.     Dimension      width;
  761.     Dimension      height;
  762.     Pixmap         pixmap;
  763. } fe_bitmap_info;
  764.  
  765. #define line_feed_width 7
  766. #define line_feed_height 10
  767. static unsigned char line_feed_bits[] = { /* lifted from Lucid Emacs */
  768.     0x00, 0xbc, 0xfc, 0xe0, 0xe0, 0x72, 0x3e, 0x1e, 0x1e, 0x3e};
  769. #define page_mark_width 8
  770. #define page_mark_height 15
  771. static char page_mark_bits[] = { /* from RobinS */
  772.  0xfe,0x4f,0x4f,0x4f,0x4f,0x4e,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48};
  773.  
  774. static fe_bitmap_info fe_line_feed_bitmap =
  775. { line_feed_bits, line_feed_width, line_feed_height };
  776. static fe_bitmap_info fe_page_mark_bitmap =
  777. { page_mark_bits, page_mark_width, page_mark_height };
  778.  
  779. static Display* fe_line_feed_display;
  780.  
  781. static Pixmap
  782. fe_make_line_feed_pixmap(Display* display, int type,
  783.              Dimension* r_width, Dimension* r_height)
  784. {
  785.     fe_bitmap_info* info;
  786.  
  787.     if (type == LO_LINEFEED_BREAK_PARAGRAPH)
  788.     info = &fe_page_mark_bitmap;
  789.     else
  790.     info = &fe_line_feed_bitmap;
  791.  
  792.     if (fe_line_feed_display != display && fe_line_feed_display != 0) {
  793.     if (info->pixmap != 0)
  794.         XFreePixmap(fe_line_feed_display, info->pixmap);
  795.     }
  796.  
  797.     if (info->pixmap == 0) {
  798.  
  799.     info->pixmap = XCreateBitmapFromData(display,
  800.                          DefaultRootWindow(display),
  801.                          info->bits,
  802.                          info->width,
  803.                          info->height);
  804.      
  805.     fe_line_feed_display = display;
  806.     }
  807.  
  808.     *r_width = info->width;
  809.     *r_height = info->height;
  810.     
  811.     return info->pixmap;
  812. }
  813.  
  814. #endif /*EDITOR*/
  815.  
  816. /* Display a glyph representing a linefeed at the given location with the
  817.    given attributes.  This looks just like a " " character.  (What is
  818.    iLocation?  It is ignored.)
  819.  */
  820. void
  821. XFE_DisplayLineFeed (MWContext *context,
  822.             int iLocation, LO_LinefeedStruct *line_feed, XP_Bool need_bg)
  823. {
  824.   GC gc;
  825.   XGCValues gcv;
  826.   unsigned long flags;
  827.   LO_TextAttr *text = line_feed->text_attr;
  828.  
  829. #ifdef EDITOR
  830.   if (EDT_IS_EDITOR(context)
  831.       &&
  832.       EDT_DISPLAY_PARAGRAPH_MARKS(context)
  833.       &&
  834.       (line_feed->break_type != LO_LINEFEED_BREAK_SOFT)
  835.       &&
  836.       (!line_feed->prev || line_feed->prev->lo_any.edit_offset >= 0)) {
  837.  
  838.       LO_Color* fg_color;
  839.       Display*  display = XtDisplay(CONTEXT_WIDGET(context));
  840.       Window    window = XtWindow(CONTEXT_DATA(context)->drawing_area);
  841.       Position  target_x;
  842.       Position  target_y;
  843.       Dimension width;
  844.       Dimension height;
  845.       Pixmap    bitmap;
  846.  
  847.       bitmap = fe_make_line_feed_pixmap(display,
  848.                     line_feed->break_type,
  849.                     &width,
  850.                     &height);
  851.       
  852.       target_x = line_feed->x + line_feed->x_offset
  853.              - CONTEXT_DATA(context)->document_x;
  854.  
  855.       target_y = line_feed->y + line_feed->y_offset
  856.          - CONTEXT_DATA(context)->document_y;
  857.  
  858.       memset (&gcv, ~0, sizeof (gcv));
  859.  
  860.       if ((line_feed->ele_attrmask & LO_ELE_SELECTED) != 0)
  861.       fg_color = &text->bg; /* layout delivers inverted colors */
  862.       else
  863.       fg_color = &text->fg;
  864.  
  865.       gcv.foreground = fe_GetPixel(context,
  866.                    fg_color->red,
  867.                    fg_color->green,
  868.                    fg_color->blue);
  869.       gcv.graphics_exposures = False;
  870.       gcv.clip_mask = bitmap;
  871.       gcv.clip_x_origin = target_x;
  872.       gcv.clip_y_origin = target_y;
  873.  
  874.       flags = GCClipMask|GCForeground|GCClipXOrigin| \
  875.           GCClipYOrigin|GCGraphicsExposures;
  876.  
  877.       gc = fe_GetGC(CONTEXT_DATA(context)->drawing_area, flags, &gcv);
  878.  
  879.       if (height > line_feed->height)
  880.       height = line_feed->height;
  881.  
  882.       XCopyPlane(display, bitmap, window,
  883.          gc,
  884.          0, 0, width, height,
  885.          target_x, target_y,
  886.          1L);
  887.   }
  888. #endif /*EDITOR*/
  889. }
  890.  
  891. /* Display a horizontal line at the given location.
  892.  */
  893. void
  894. XFE_DisplayHR (MWContext *context, int iLocation, LO_HorizRuleStruct *hr)
  895. {
  896.   int shadow_width = 1;            /* #### customizable? */
  897.   int shadow_style = XmSHADOW_IN;    /* #### customizable? */
  898.   int thickness = hr->thickness;
  899.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  900.   Drawable drawable = fe_drawable->xdrawable;
  901.   long x = hr->x + hr->x_offset - CONTEXT_DATA (context)->document_x +
  902.       fe_drawable->x_origin;
  903.   long y = hr->y + hr->y_offset - CONTEXT_DATA (context)->document_y +
  904.       fe_drawable->y_origin;
  905.   int w = hr->width;
  906.  
  907.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  908.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  909.       (x + hr->width < 0) ||
  910.       (y + hr->line_height < 0))
  911.     return;
  912.  
  913.   thickness -= (shadow_width * 2);
  914.   if (thickness < 0) thickness = 0;
  915.  
  916. #ifdef EDITOR
  917.   /*
  918.    *    Don't draw the editor's end-of-document hrule unless we're
  919.    *    displaying paragraph marks.
  920.    */
  921.   if (hr->edit_offset < 0 && !EDT_DISPLAY_PARAGRAPH_MARKS(context)) {
  922.       return;
  923.   }
  924. #endif /* EDITOR */
  925.  
  926.   if (hr->ele_attrmask & LO_ELE_SHADED)
  927.     {
  928. #ifdef EDITOR
  929.     fe_DrawSelectedShadows(context, fe_drawable,
  930.                    x, y, w, thickness + (shadow_width * 2),
  931.                    shadow_width, shadow_style,
  932.                    ((hr->ele_attrmask & LO_ELE_SELECTED) != 0));
  933. #else
  934.     fe_DrawShadows (context, fe_drawable, x, y, w,
  935.                         thickness + (shadow_width * 2),
  936.                         shadow_width, shadow_style);
  937. #endif /* EDITOR */
  938.     }
  939.   else
  940.     {
  941.       Display *dpy = XtDisplay (CONTEXT_DATA (context)->drawing_area);
  942.       GC gc;
  943.       XGCValues gcv;
  944.  
  945.       memset (&gcv, ~0, sizeof(gcv));
  946.       gcv.foreground = CONTEXT_DATA(context)->fg_pixel;
  947.       gc = fe_GetClipGC(CONTEXT_WIDGET (context), GCForeground, &gcv,
  948.                         fe_drawable->clip_region);
  949.       XFillRectangle(dpy, drawable, gc, x, y, w, hr->height);
  950. #ifdef EDITOR
  951.       if ((hr->ele_attrmask & LO_ELE_SELECTED) != 0) {
  952.       gcv.background = CONTEXT_DATA(context)->select_bg_pixel;
  953.       gcv.line_width = 1;
  954.       gcv.line_style = LineDoubleDash;
  955.       gc = fe_GetGC(CONTEXT_WIDGET(context),
  956.             GCForeground|GCBackground|GCLineWidth|GCLineStyle,
  957.             &gcv);
  958.       XDrawRectangle(dpy, drawable, gc, x, y, w-1, hr->height-1);
  959.       }
  960. #endif /* EDITOR */
  961.     }
  962. }
  963.  
  964. void
  965. XFE_DisplayBullet (MWContext *context, int iLocation, LO_BulletStruct *bullet)
  966. {
  967.   int w,h;
  968.   Boolean hollow_p;
  969.   GC gc;
  970.   Drawable drawable;
  971.  
  972.   Widget widget = CONTEXT_WIDGET (context);
  973.   Display *dpy = XtDisplay (widget);
  974.  
  975.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  976.   long x = bullet->x + bullet->x_offset - CONTEXT_DATA (context)->document_x +
  977.       fe_drawable->x_origin;
  978.   long y = bullet->y + bullet->y_offset - CONTEXT_DATA (context)->document_y +
  979.       fe_drawable->y_origin;
  980.   drawable = fe_drawable->xdrawable;
  981.   w = bullet->width;
  982.   h = bullet->height;
  983.   hollow_p = (bullet->bullet_type != BULLET_BASIC);
  984.  
  985.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  986.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  987.       (x + w < 0) ||
  988.       (y + h < 0))
  989.     return;
  990.  
  991.   gc = fe_get_text_gc (context, bullet->text_attr, 0, 0, False);
  992.   if (!gc)
  993.   {
  994.     return;
  995.   }
  996.   switch (bullet->bullet_type)
  997.     {
  998.     case BULLET_BASIC:
  999.     case BULLET_ROUND:
  1000.       /* Subtract 1 to compensate for the behavior of XDrawArc(). */
  1001.       w -= 1;
  1002.       h -= 1;
  1003.       /* Now round up to an even number so that the circles look nice. */
  1004.       if (! (w & 1)) w++;
  1005.       if (! (h & 1)) h++;
  1006.       if (hollow_p)
  1007.     XDrawArc (dpy, drawable, gc, x, y, w, h, 0, 360*64);
  1008.       else
  1009.     XFillArc (dpy, drawable, gc, x, y, w, h, 0, 360*64);
  1010.       break;
  1011.     case BULLET_SQUARE:
  1012.       if (hollow_p)
  1013.     XDrawRectangle (dpy, drawable, gc, x, y, w, h);
  1014.       else
  1015.     XFillRectangle (dpy, drawable, gc, x, y, w, h);
  1016.       break;
  1017.     case BULLET_MQUOTE:
  1018.         /*
  1019.          * WARNING... [ try drawing a 2 pixel wide filled rectangle ]
  1020.          *
  1021.          *
  1022.          */
  1023. #ifdef DOH_WHICH_ONE
  1024.         XDrawLine (dpy, drawable, gc, x, y, x, (y + h));
  1025. #else
  1026.         w = 2;
  1027.         XFillRectangle (dpy, drawable, gc, x, y, w, h);
  1028. #endif
  1029.         break;
  1030.  
  1031.     case BULLET_NONE:
  1032.         /* Do nothing. */
  1033.         break;
  1034.  
  1035.     default:
  1036.         XP_ASSERT(0);
  1037.     }
  1038. }
  1039.  
  1040. void
  1041. XFE_DisplaySubDoc (MWContext *context, int loc, LO_SubDocStruct *sd)
  1042. {
  1043.   int shadow_style = XmSHADOW_IN;    /* #### customizable? */
  1044.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1045.   /*Drawable drawable = fe_drawable->xdrawable;*/
  1046.   long x = sd->x + sd->x_offset - CONTEXT_DATA (context)->document_x +
  1047.       fe_drawable->x_origin;
  1048.   long y = sd->y + sd->y_offset - CONTEXT_DATA (context)->document_y +
  1049.       fe_drawable->y_origin;
  1050.  
  1051.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  1052.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  1053.       (x + sd->width < 0) ||
  1054.       (y + sd->line_height< 0))
  1055.     return;
  1056.  
  1057.   fe_DrawShadows (context, fe_drawable, x, y, sd->width, sd->height,
  1058.           sd->border_width, shadow_style);
  1059. }
  1060.  
  1061. void
  1062. XFE_DisplayCell (MWContext *context, int loc, LO_CellStruct *cell)
  1063. {
  1064.   int shadow_style = XmSHADOW_IN;    /* #### customizable? */
  1065.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1066.   long x = cell->x + cell->x_offset - CONTEXT_DATA (context)->document_x +
  1067.       fe_drawable->x_origin;
  1068.   long y = cell->y + cell->y_offset - CONTEXT_DATA (context)->document_y +
  1069.       fe_drawable->y_origin;
  1070.   int border_width = cell->border_width;
  1071.  
  1072.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  1073.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  1074.       (x + cell->width < 0) ||
  1075.       (y + cell->line_height< 0))
  1076.     return;
  1077.  
  1078. #ifdef EDITOR
  1079.   if (EDT_IS_EDITOR(context))
  1080.   {
  1081.       Boolean selected = ((cell->ele_attrmask & LO_ELE_SELECTED) != 0);
  1082.       fe_DrawSelectedShadows (context, fe_drawable,
  1083.                               x, y, cell->width, cell->height,
  1084.                               border_width, shadow_style, selected);
  1085.   }
  1086.   else
  1087. #endif /* EDITOR */
  1088.   fe_DrawShadows (context, fe_drawable, x, y, cell->width, cell->height,
  1089.                   cell->border_width, shadow_style);
  1090. }
  1091.  
  1092. typedef struct
  1093. {
  1094.   Dimension left;
  1095.   Dimension top;
  1096.   Dimension right;
  1097.   Dimension bottom;
  1098. } FE_BorderWidths;
  1099.  
  1100. static void
  1101. fe_DisplaySolidBorder(MWContext *context, LO_TableStruct *ts,
  1102.                       XRectangle *rect, FE_BorderWidths *widths)
  1103. {
  1104.   XGCValues gcv;
  1105.   unsigned long gc_flags;
  1106.   GC gc;
  1107.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1108.  
  1109.   /* if they're all the same width, just vary the line thickness and use XDrawRectangle */
  1110.   if (widths->left == widths->top && widths->left == widths->right && widths->left == widths->bottom)
  1111.     {
  1112.       gc_flags = GCForeground | GCLineWidth;
  1113.  
  1114.       gcv.foreground = fe_GetPixel(context, 
  1115.                                    ts->border_color.red,
  1116.                                    ts->border_color.green,
  1117.                                    ts->border_color.blue);
  1118.  
  1119.       gcv.line_width = widths->left; /* doesn't really matter which one we choose. */
  1120.  
  1121.           if (ts->border_style == BORDER_DASHED
  1122.               || ts->border_style == BORDER_DOTTED)
  1123.           {
  1124.               gc_flags |= GCLineStyle;
  1125.               gcv.line_style = LineOnOffDash;
  1126.           }
  1127.  
  1128.       gc = fe_GetGCfromDW(fe_display, fe_drawable->xdrawable, gc_flags, &gcv, fe_drawable->clip_region);
  1129.  
  1130.       rect->x += widths->left / 2;
  1131.       rect->y += widths->left / 2;
  1132.       rect->width -= widths->left;
  1133.       rect->height -= widths->left;
  1134.  
  1135.       XDrawRectangle(fe_display,
  1136.                      XtWindow(CONTEXT_DATA(context)->drawing_area),
  1137.                      gc,
  1138.                      rect->x, rect->y, rect->width, rect->height);
  1139.           /* set the line attributes back to solid in case we changed them */
  1140.           if (ts->border_style == BORDER_DASHED
  1141.               || ts->border_style == BORDER_DOTTED)
  1142.           {
  1143.               gc_flags = GCLineStyle;
  1144.               gcv.line_style = LineSolid;     /* should get previous value? */
  1145.               XChangeGC(fe_display, gc, gc_flags, &gcv);
  1146.           }
  1147.     }
  1148.   else
  1149.     {
  1150.       /* since they are (possibly) all different, we do each border will XFillRectangle */
  1151.       gc_flags = GCForeground;
  1152.  
  1153.       gcv.foreground = fe_GetPixel(context,
  1154.                                    ts->border_color.red,
  1155.                                    ts->border_color.green,
  1156.                                    ts->border_color.blue);
  1157.  
  1158.  
  1159.       gc = fe_GetGCfromDW(fe_display, fe_drawable->xdrawable, gc_flags, &gcv, fe_drawable->clip_region);
  1160.  
  1161.       if (widths->left > 0)
  1162.         XFillRectangle(fe_display,
  1163.                        XtWindow(CONTEXT_DATA(context)->drawing_area),
  1164.                        gc,
  1165.                        rect->x, rect->y, widths->left, rect->height);
  1166.  
  1167.       if (widths->top > 0)
  1168.         XFillRectangle(fe_display,
  1169.                        XtWindow(CONTEXT_DATA(context)->drawing_area),
  1170.                        gc,
  1171.                        rect->x, rect->y, rect->width, widths->top);
  1172.  
  1173.       if (widths->right > 0)
  1174.         XFillRectangle(fe_display,
  1175.                        XtWindow(CONTEXT_DATA(context)->drawing_area),
  1176.                        gc,
  1177.                        rect->x + rect->width - widths->right, rect->y, widths->right, rect->height);
  1178.  
  1179.       if (widths->bottom > 0)
  1180.         XFillRectangle(fe_display,
  1181.                        XtWindow(CONTEXT_DATA(context)->drawing_area),
  1182.                        gc,
  1183.                        rect->x, rect->y + rect->height - widths->bottom, rect->width, widths->bottom);
  1184.     }
  1185. }
  1186.  
  1187. static void
  1188. fe_DisplayDoubleBorder(MWContext *context, LO_TableStruct *ts,
  1189.                        XRectangle *rect, FE_BorderWidths *widths)
  1190. {
  1191.   FE_BorderWidths stroke_widths;
  1192.  
  1193.   stroke_widths.left = (widths->left + 1) / 3;
  1194.   stroke_widths.top = (widths->top + 1) / 3;
  1195.   stroke_widths.right = (widths->right + 1) / 3;
  1196.   stroke_widths.bottom = (widths->bottom + 1) / 3;
  1197.  
  1198.   /* draw the outer lines */
  1199.   fe_DisplaySolidBorder(context, ts, rect, &stroke_widths);
  1200.  
  1201.   /* adjust the rectangle to be the inner one */
  1202.   rect->x += (widths->left - stroke_widths.left);
  1203.   rect->y += (widths->top - stroke_widths.top);
  1204.   rect->width -= (widths->right - stroke_widths.right) + (widths->left - stroke_widths.left);
  1205.   rect->height -= (widths->bottom - stroke_widths.bottom) + (widths->top - stroke_widths.top);
  1206.  
  1207.   /* draw the inner lines */
  1208.   fe_DisplaySolidBorder(context, ts, rect, &stroke_widths);
  1209. }
  1210.  
  1211. /* warning.  much of this gc related code is duplicated from the fe_DrawSelectedShadows function above */
  1212. static void
  1213. fe_Display3DBorder(MWContext *context, LO_TableStruct *ts,
  1214.                    XRectangle *rect, FE_BorderWidths *widths,
  1215.                    Pixel top_shadow, Pixel bottom_shadow)
  1216. {
  1217.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1218.   XGCValues gcv1, gcv2;
  1219.   unsigned long gc_flags = GCForeground;
  1220.   GC gc1, gc2;
  1221.  
  1222.   memset (&gcv1, ~0, sizeof (gcv1));
  1223.   memset (&gcv2, ~0, sizeof (gcv2));
  1224.  
  1225.   if (CONTEXT_DATA (context)->backdrop_pixmap ||
  1226.       CONTEXT_DATA (context)->bg_pixel !=
  1227.       CONTEXT_DATA (context)->default_bg_pixel)
  1228.     {
  1229.       static Pixmap gray50 = 0;
  1230.       if (! gray50)
  1231.         {
  1232. #      define gray50_width  8
  1233. #      define gray50_height 2
  1234.           static char gray50_bits[] = { 0x55, 0xAA };
  1235.           gray50 =
  1236.             XCreateBitmapFromData (fe_display,
  1237.                                    RootWindowOfScreen (XtScreen (CONTEXT_WIDGET(context))),
  1238.                                    gray50_bits, gray50_width, gray50_height);
  1239.         }
  1240.       gc_flags = (GCForeground | GCStipple | GCFillStyle |
  1241.                   GCTileStipXOrigin | GCTileStipYOrigin);
  1242.       
  1243.       gcv1.fill_style = FillStippled;
  1244.       gcv1.stipple = gray50;
  1245.       gcv1.ts_x_origin = -CONTEXT_DATA (context)->document_x;
  1246.       gcv1.ts_y_origin = -CONTEXT_DATA (context)->document_y;
  1247.       gcv1.foreground = fe_GetPixel (context, 0xFF, 0xFF, 0xFF);
  1248.       gcv2 = gcv1;
  1249.       gcv2.foreground = fe_GetPixel (context, 0x00, 0x00, 0x00);
  1250.     }
  1251.   else
  1252.     {
  1253.       gc_flags = GCForeground;
  1254.       gcv1.foreground = top_shadow;
  1255.       gcv2.foreground = bottom_shadow;
  1256.     }
  1257.   
  1258.   gc1 = fe_GetGCfromDW (fe_display, fe_drawable->xdrawable, gc_flags, &gcv1, fe_drawable->clip_region);
  1259.   gc2 = fe_GetGCfromDW (fe_display, fe_drawable->xdrawable, gc_flags, &gcv2, fe_drawable->clip_region);
  1260.   
  1261.   if (widths->left == widths->top && widths->left == widths->right && widths->left == widths->bottom)
  1262.     {
  1263.       _XmDrawShadows(fe_display,
  1264.                      fe_drawable->xdrawable,
  1265.                      gc1, gc2, rect->x, rect->y, rect->width, rect->height,
  1266.                      widths->left, XmSHADOW_OUT);
  1267.     }
  1268.   else
  1269.     {
  1270.       XPoint points[6];
  1271.  
  1272.       points[0].x = rect->x + widths->left;
  1273.       points[0].y = rect->y + widths->top;
  1274.       points[1].x = rect->x + widths->left;
  1275.       points[1].y = rect->y + rect->height - widths->bottom;
  1276.       points[2].x = rect->x;
  1277.       points[2].y = rect->y + rect->height;
  1278.       points[3].x = rect->x;
  1279.       points[3].y = rect->y;
  1280.       points[4].x = rect->x + rect->width;
  1281.       points[4].y = rect->y;
  1282.       points[5].x = rect->x + rect->width - widths->right;
  1283.       points[5].y = rect->y + widths->top;
  1284.       
  1285.       XFillPolygon(fe_display,
  1286.                    fe_drawable->xdrawable,
  1287.                    gc1,
  1288.                    points, 6, 
  1289.                    Nonconvex,
  1290.                    CoordModeOrigin);
  1291.  
  1292.       points[0].x = rect->x + rect->width - widths->right;
  1293.       points[0].y = rect->y + rect->height - widths->bottom;
  1294.       points[3].x = rect->x + rect->width;
  1295.       points[3].y = rect->y + rect->height;
  1296.  
  1297.       XFillPolygon(fe_display,
  1298.                    fe_drawable->xdrawable,
  1299.                    gc2,
  1300.                    points, 6, 
  1301.                    Nonconvex,
  1302.                    CoordModeOrigin);
  1303.     }
  1304. }
  1305.  
  1306. static void
  1307. fe_DisplayTableBorder(MWContext *context, LO_TableStruct *ts,
  1308.                       XRectangle *rect, FE_BorderWidths *widths)
  1309. {
  1310.   Pixel table_color, top_color, bottom_color;
  1311.   XRectangle inset_rect;
  1312.   
  1313.   if (ts->border_style == BORDER_GROOVE
  1314.       || ts->border_style == BORDER_RIDGE
  1315.       || ts->border_style == BORDER_INSET
  1316.       || ts->border_style == BORDER_OUTSET)
  1317.     {
  1318.       table_color = fe_GetPixel(context,
  1319.                                 ts->border_color.red,
  1320.                                 ts->border_color.green,
  1321.                                 ts->border_color.blue);
  1322.       
  1323.       XmGetColors(XtScreen(CONTEXT_WIDGET(context)),
  1324.                   fe_cmap(context),
  1325.                   table_color,
  1326.                   NULL,
  1327.                   &top_color, &bottom_color,
  1328.                   NULL);
  1329.     }
  1330.       
  1331.   switch (ts->border_style)
  1332.     {
  1333.     case BORDER_NONE:
  1334.       break;
  1335.  
  1336.     case BORDER_DOTTED:
  1337.     case BORDER_DASHED:
  1338.     case BORDER_SOLID:
  1339.       fe_DisplaySolidBorder(context, ts, rect, widths);
  1340.       break;
  1341.  
  1342.     case BORDER_DOUBLE:
  1343.       fe_DisplayDoubleBorder(context, ts, rect, widths);
  1344.       break;
  1345.  
  1346.     case BORDER_GROOVE:
  1347.       widths->left /= 2;
  1348.       widths->top /= 2;
  1349.       widths->right /= 2;
  1350.       widths->bottom /= 2;
  1351.       fe_Display3DBorder(context, ts, rect, widths, bottom_color, top_color);
  1352.       inset_rect.x = rect->x + widths->left;
  1353.       inset_rect.y = rect->y + widths->top;
  1354.       inset_rect.width = rect->width - widths->left - widths->right;
  1355.       inset_rect.height = rect->height - widths->top - widths->bottom;
  1356.       fe_Display3DBorder(context, ts, &inset_rect, widths, top_color, bottom_color);
  1357.       break;
  1358.  
  1359.     case BORDER_RIDGE:
  1360.       widths->left /= 2;
  1361.       widths->top /= 2;
  1362.       widths->right /= 2;
  1363.       widths->bottom /= 2;
  1364.       fe_Display3DBorder(context, ts, rect, widths, top_color, bottom_color);
  1365.       inset_rect.x = rect->x + widths->left;
  1366.       inset_rect.y = rect->y + widths->top;
  1367.       inset_rect.width = rect->width - widths->left - widths->right;
  1368.       inset_rect.height = rect->height - widths->top - widths->bottom;
  1369.       fe_Display3DBorder(context, ts, &inset_rect, widths, bottom_color, top_color);
  1370.       break;
  1371.  
  1372.     case BORDER_INSET:
  1373.       fe_Display3DBorder(context, ts, rect, widths, bottom_color, top_color);
  1374.       break;
  1375.  
  1376.     case BORDER_OUTSET:
  1377.       fe_Display3DBorder(context, ts, rect, widths, top_color, bottom_color);
  1378.       break;
  1379.  
  1380.     default:
  1381.       XP_ASSERT(0);
  1382.       break;
  1383.     }
  1384. }
  1385.  
  1386. #define ED_SELECTION_BORDER 3
  1387.  
  1388. void
  1389. XFE_DisplayTable (MWContext *context, int loc, LO_TableStruct *ts)
  1390. {
  1391.   XP_Bool hasBorder;
  1392.   int32 savedBorderStyle;
  1393.   LO_Color savedBorderColor;
  1394.   XRectangle table_rect;
  1395.   FE_BorderWidths widths;
  1396.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1397.   long x = ts->x + ts->x_offset - CONTEXT_DATA (context)->document_x +
  1398.       fe_drawable->x_origin;
  1399.   long y = ts->y + ts->y_offset - CONTEXT_DATA (context)->document_y +
  1400.       fe_drawable->y_origin;
  1401.  
  1402.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  1403.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  1404.       (x + ts->width < 0) ||
  1405.       (y + ts->line_height< 0))
  1406.     return;
  1407.  
  1408.   hasBorder = (ts->border_top_width > 0 || ts->border_right_width > 0
  1409.                 || ts->border_bottom_width > 0 || ts->border_left_width > 0);
  1410.  
  1411.   /* Set the border rect if we have a border or if the table is selected */
  1412.   table_rect.x = x;
  1413.   table_rect.y = y;
  1414.   table_rect.width = ts->width;
  1415.   table_rect.height = ts->height;
  1416.  
  1417. #ifdef EDITOR
  1418.   /* Figure out the boundaries for the selection highlight.
  1419.    * This needs to be done whether or not we're selected,
  1420.    * because we may have to clear the selection (but only in the editor).
  1421.    * Some of this code is stolen from the macfe.
  1422.    */
  1423.   if (EDT_IS_EDITOR(context))
  1424.   {
  1425.       int iSelectionBorderThickness;
  1426.       XGCValues gcv;
  1427.       unsigned long gc_flags;
  1428.       GC gc;
  1429.       fe_Drawable *fe_drawable = CONTEXT_DATA(context)->drawable;
  1430.  
  1431.       /* This is what the macfe does, but on X it's slow.
  1432.        * lo_DisplayLine ends up calling lo_DisplayTable for every
  1433.        * table element!  This has something to do with the entropy
  1434.        * calculated for the layer in liblayer/cl_util.h, which causes
  1435.        * the table to be laid out cell by cell even if the whole page
  1436.        * is being redisplayed; and the table border gets entirely
  1437.        * redrawn for each of these redraws.  Yuck!
  1438.        */
  1439.  
  1440.       /* set the border thickness to be the minimum of all border widths */
  1441.       if (!hasBorder && (0 == ts->inter_cell_space))
  1442.           iSelectionBorderThickness = 1;
  1443.       else
  1444.       {
  1445.           iSelectionBorderThickness = ts->border_left_width;
  1446.           if ( ts->border_right_width < iSelectionBorderThickness )
  1447.               iSelectionBorderThickness = ts->border_right_width;
  1448.           if ( ts->border_top_width < iSelectionBorderThickness )
  1449.               iSelectionBorderThickness = ts->border_top_width;
  1450.           if ( ts->border_bottom_width < iSelectionBorderThickness )
  1451.               iSelectionBorderThickness = ts->border_bottom_width;
  1452.  
  1453.           /* allow for a larger selection if the border is large */
  1454.           if ( iSelectionBorderThickness > 2 * ED_SELECTION_BORDER )
  1455.               iSelectionBorderThickness = 2 * ED_SELECTION_BORDER;
  1456.  
  1457.       /* else if the area is too small, use the spacing between cells */
  1458.           else if ( iSelectionBorderThickness < ED_SELECTION_BORDER )
  1459.           {
  1460.               iSelectionBorderThickness += ts->inter_cell_space;
  1461.  
  1462.               /* but don't use it all; stick to the minimal amount */
  1463.               if ( iSelectionBorderThickness > ED_SELECTION_BORDER )
  1464.                   iSelectionBorderThickness = ED_SELECTION_BORDER;
  1465.           }
  1466.       }
  1467.  
  1468.       if (ts->ele_attrmask & LO_ELE_SELECTED)
  1469.       {
  1470.           gc_flags = GCForeground | GCLineWidth | GCLineStyle;
  1471.           gcv.foreground = CONTEXT_DATA(context)->select_bg_pixel;
  1472.           gcv.line_style = LineOnOffDash;
  1473.       }
  1474.       else
  1475.       {
  1476.           gc_flags = GCForeground | GCLineWidth;
  1477.           gcv.foreground =
  1478.               CONTEXT_DATA(context)->drawing_area->core.background_pixel;
  1479.       }
  1480.  
  1481.       gcv.line_width = iSelectionBorderThickness;
  1482.       gc = fe_GetGCfromDW(fe_display, fe_drawable->xdrawable,
  1483.                           gc_flags, &gcv, fe_drawable->clip_region);
  1484.       XDrawRectangle(fe_display,
  1485.                      XtWindow(CONTEXT_DATA(context)->drawing_area), gc,
  1486.                      table_rect.x, table_rect.y,
  1487.                      table_rect.width-1, table_rect.height-1);
  1488.   } /* end showing selection highlight if editor */
  1489. #endif /* EDITOR */
  1490.  
  1491.   if (hasBorder)
  1492.   {
  1493.       widths.top = ts->border_top_width;
  1494.       widths.right = ts->border_right_width;
  1495.       widths.bottom = ts->border_bottom_width;
  1496.       widths.left = ts->border_left_width;
  1497.       fe_DisplayTableBorder(context, ts, &table_rect, &widths);
  1498.   }
  1499. }
  1500.  
  1501. typedef struct _SashInfo {
  1502.   Widget sash;
  1503.   Widget separator;
  1504.   LO_EdgeStruct *edge;
  1505.   MWContext *context;
  1506.   time_t last;
  1507. } SashInfo;
  1508.  
  1509. static void
  1510. fe_sash_cb (Widget widget, XtPointer closure, XtPointer call_data)
  1511. {
  1512.   SashInfo *sashinfo = (SashInfo *) closure;
  1513.   MWContext *context;
  1514.   LO_EdgeStruct *edge;
  1515.   SashCallData sash_data = (SashCallData) call_data;
  1516.  
  1517.   static EventMask activity = 0;
  1518.   static GC trackgc = 0;
  1519.   static int lastx = 0;
  1520.   static int lasty = 0;
  1521.   static int lastw = 0;
  1522.   static int lasth = 0;
  1523.  
  1524.   TRACEMSG (("fe_sash_cb\n"));
  1525.  
  1526.   if (!sashinfo) return;
  1527.   context = sashinfo->context;
  1528.   edge = sashinfo->edge;
  1529.  
  1530.   switch (sash_data->event->xany.type) {
  1531.   case ButtonPress: {
  1532.       XGCValues values;
  1533.       unsigned long valuemask;
  1534.  
  1535.       if (activity) return;
  1536.       activity = ButtonPressMask;
  1537.  
  1538.       if (!trackgc) {
  1539.     valuemask = GCForeground | GCSubwindowMode | GCFunction;
  1540.     values.foreground = CONTEXT_DATA (context)->default_bg_pixel;
  1541.     values.subwindow_mode = IncludeInferiors;
  1542.     values.function = GXinvert;
  1543.     trackgc = XCreateGC (XtDisplay (widget),
  1544.                  XtWindow (CONTEXT_WIDGET (context)),
  1545.                  valuemask, &values);
  1546.       }
  1547.     }
  1548.     break;
  1549.   case ButtonRelease:
  1550.     if (activity & PointerMotionMask) {
  1551.       static time_t last = 0;
  1552.       time_t now;
  1553.  
  1554.       /* Clean up the last line drawn */
  1555.       XDrawLine (XtDisplay (widget),
  1556.            XtWindow (CONTEXT_DATA (context)->drawing_area),
  1557.            trackgc, lastx, lasty, lastw, lasth);
  1558.  
  1559.       activity = 0; /* make sure we clear this for next time */
  1560.  
  1561.       if (trackgc) XFreeGC (XtDisplay (widget), trackgc);
  1562.       trackgc = 0;
  1563.  
  1564.       /* What's the scrolling policy for this context? */
  1565.       if (!edge->movable)
  1566.     return;
  1567.  
  1568.       /* Don't thrash */
  1569.       now = time ((time_t) 0);
  1570.       if (now > last)
  1571.         LO_MoveGridEdge (context, edge, lastx, lasty);
  1572.       last = now;
  1573.  
  1574.       lastx = lasty = lastw = lasth = 0;
  1575.     }
  1576.     break;
  1577.   case MotionNotify: {
  1578.       Display *dpy = XtDisplay (widget);
  1579.       Window kid;
  1580.       int da_x, da_y;
  1581.  
  1582.       if (!(activity & ButtonPressMask)) return;
  1583.  
  1584.       /* What's the scrolling policy for this context? */
  1585.       if (!edge->movable)
  1586.     return;
  1587.  
  1588.       /* Now that we know we're going to do something */
  1589.       activity |= PointerMotionMask;
  1590.  
  1591.       XTranslateCoordinates(dpy,
  1592.                             XtWindow (CONTEXT_DATA (context)->drawing_area),
  1593.                             DefaultRootWindow (dpy),
  1594.                             0, 0, &da_x, &da_y, &kid);
  1595.  
  1596.       if (lastw && lasth)
  1597.         XDrawLine (XtDisplay (widget),
  1598.            XtWindow (CONTEXT_DATA (context)->drawing_area),
  1599.            trackgc, lastx, lasty, lastw, lasth);
  1600.  
  1601.       if (edge->is_vertical)
  1602.         {
  1603.           int cx = sash_data->event->xmotion.x_root;
  1604.  
  1605.       lastx = cx - da_x;
  1606.       lasty = edge->y + edge->y_offset;
  1607.  
  1608.       if (lastx < edge->left_top_bound + 20)
  1609.         lastx = edge->left_top_bound + 20;
  1610.  
  1611.       if (lastx > edge->right_bottom_bound - 20)
  1612.         lastx = edge->right_bottom_bound - 20;
  1613.  
  1614.       lastw = lastx;
  1615.       lasth = lasty + edge->height - 1;
  1616.         }
  1617.       else
  1618.         {
  1619.           int cy = sash_data->event->xmotion.y_root;
  1620.  
  1621.       lastx = edge->x + edge->x_offset;
  1622.       lasty = cy - da_y;
  1623.  
  1624.       if (lasty < edge->left_top_bound + 20)
  1625.         lasty = edge->left_top_bound + 20;
  1626.  
  1627.       if (lasty > edge->right_bottom_bound - 20)
  1628.         lasty = edge->right_bottom_bound - 20;
  1629.  
  1630.       lastw = lastx + edge->width - 1;
  1631.       lasth = lasty;
  1632.         }
  1633.  
  1634.       XDrawLine (XtDisplay (widget),
  1635.          XtWindow (CONTEXT_DATA (context)->drawing_area),
  1636.          trackgc, lastx, lasty, lastw, lasth);
  1637.     }
  1638.     break;
  1639.   default:
  1640.     break;
  1641.   }
  1642. }
  1643.  
  1644. static void
  1645. fe_sash_destroy_cb (Widget w, XtPointer closure, XtPointer cb)
  1646. {
  1647.   SashInfo *sashinfo = (SashInfo *) closure;
  1648.   sashinfo->sash = NULL;
  1649. }
  1650.  
  1651. void
  1652. XFE_DisplayEdge (MWContext *context, int loc, LO_EdgeStruct *edge)
  1653. {
  1654.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  1655.   long x = edge->x + edge->x_offset - CONTEXT_DATA (context)->document_x +
  1656.       fe_drawable->x_origin;
  1657.   long y = edge->y + edge->y_offset - CONTEXT_DATA (context)->document_y +
  1658.       fe_drawable->y_origin;
  1659.   Widget drawing_area = CONTEXT_DATA (context)->drawing_area;
  1660.   Widget sash;
  1661.   static XtCallbackRec sashCallback[] = { {fe_sash_cb, 0}, {0, 0} };
  1662.   SashInfo *sashinfo;
  1663.   Arg av [50];
  1664.   int ac;
  1665.  
  1666.   if ((x > 0 && x > CONTEXT_DATA (context)->scrolled_width) ||
  1667.       (y > 0 && y > CONTEXT_DATA (context)->scrolled_height) ||
  1668.       (x + edge->width < 0) ||
  1669.       (y + edge->height< 0))
  1670.     return;
  1671.  
  1672.   /* Set up the args for the sash.
  1673.    * Careful! This is the only place we initialize av.
  1674.    */
  1675.   ac = 0;
  1676.   XtSetArg (av[ac], XmNx, x); ac++;
  1677.   XtSetArg (av[ac], XmNy, y); ac++;
  1678.   XtSetArg (av[ac], XmNwidth, edge->width); ac++;
  1679.   XtSetArg (av[ac], XmNheight, edge->height); ac++;
  1680.   if (edge->bg_color) {
  1681.     Pixel color = fe_GetPixel (context,
  1682.                    edge->bg_color->red,
  1683.                    edge->bg_color->green,
  1684.                    edge->bg_color->blue);
  1685.     XtSetArg (av[ac], XmNbackground, color); ac++;
  1686.   }
  1687.  
  1688.   if (edge->FE_Data) {
  1689.     time_t now = time((time_t) 0);
  1690.  
  1691.     sashinfo = (SashInfo *) edge->FE_Data;
  1692.     if (now <= sashinfo->last) return;
  1693.     sashinfo->last = now;
  1694.  
  1695.     if (sashinfo->sash) {
  1696.       XtSetValues (sashinfo->sash, av, ac);
  1697.       return;
  1698.     }
  1699.       
  1700.     edge->FE_Data = NULL;
  1701.     XP_FREE (sashinfo);
  1702.   }
  1703.  
  1704.   /* Otherwise, create and display a new one */
  1705.  
  1706.   sashinfo = (SashInfo *) XP_ALLOC (sizeof (SashInfo));
  1707.   if (!sashinfo) return;
  1708.  
  1709.   sashCallback[0].closure = (XtPointer) sashinfo;
  1710.  
  1711.   /* av and ac were initialized above */
  1712.   XtSetArg (av[ac], XmNcallback, (XtArgVal) sashCallback); ac++;
  1713.   sash = XtCreateWidget("sash", xmSashWidgetClass, drawing_area, av, ac);
  1714.   if (!edge->movable)
  1715.     XtVaSetValues (sash, XmNsensitive, False, 0);
  1716.  
  1717.   XtAddCallback (sash, XtNdestroyCallback, fe_sash_destroy_cb,
  1718.          (XtPointer) sashinfo);
  1719.   XtManageChild (sash);
  1720.  
  1721.   sashinfo->sash = sash;
  1722.   sashinfo->edge = edge;
  1723.   sashinfo->context = context;
  1724.   sashinfo->last = time((time_t) 0);
  1725.  
  1726.   edge->FE_Data = (void *) sashinfo;
  1727. }
  1728.  
  1729.  
  1730. void
  1731. XFE_SetBackgroundColor (MWContext *context, uint8 red, uint8 green,
  1732.             uint8 blue)
  1733. {
  1734.   Pixel bg = fe_GetPixel (context, red, green, blue);
  1735.   CONTEXT_DATA (context)->bg_red   = red;
  1736.   CONTEXT_DATA (context)->bg_green = green;
  1737.   CONTEXT_DATA (context)->bg_blue  = blue;
  1738.   CONTEXT_DATA (context)->bg_pixel = bg;
  1739.  
  1740. /* Set the transparent pixel color.  The transparent pixel is passed into
  1741.    calls to IL_GetImage for image requests that do not use a mask. */
  1742.   fe_SetTransparentPixel(context, red, green, blue, bg);
  1743.  
  1744.   XSetWindowBackground (XtDisplay(CONTEXT_DATA (context)->drawing_area),
  1745.             XtWindow(CONTEXT_DATA (context)->drawing_area), bg);
  1746.   CONTEXT_DATA (context)->drawing_area->core.background_pixel = bg;
  1747. }
  1748.  
  1749.  
  1750. /* XXXM12N FE_EraseBackground needs to be completely restructured.  The way
  1751.    it is planned, layout would only call FE_EraseBackground to clear an
  1752.    area with a solid color.  Backdrop pixmaps would be handled by calling
  1753.    IL_DisplaySubImage, which can perform tiling if necessary. */
  1754. /* Erase the background at the given rect. x, y, width and height are */
  1755. /* in document coordinates. */
  1756. void
  1757. XFE_EraseBackground(MWContext *context, int iLocation, int32 x, int32 y,
  1758.                     uint32 width, uint32 height, LO_Color *bg)
  1759. {
  1760.     if (width > 0 && height > 0) {
  1761.         if (bg) {
  1762.             Pixel color = fe_GetPixel(context, bg->red, bg->green, bg->blue);
  1763.             fe_ClearAreaWithColor(context,
  1764.                                   -CONTEXT_DATA(context)->document_x + x,
  1765.                                   -CONTEXT_DATA(context)->document_y + y,
  1766.                                   width, height, color);
  1767.         }
  1768.         else {
  1769.             fe_ClearArea(context,
  1770.                          -CONTEXT_DATA(context)->document_x + x,
  1771.                          -CONTEXT_DATA(context)->document_y + y,
  1772.                          width, height);
  1773.         }
  1774.     }
  1775. }
  1776.  
  1777. void
  1778. FE_GetEdgeMinSize(MWContext *context, int32 *size_p)
  1779. {
  1780.     *size_p = 5;
  1781. }
  1782.  
  1783.  
  1784. void
  1785. FE_GetFullWindowSize(MWContext *context, int32 *width, int32 *height)
  1786. {
  1787.   Dimension     w = 0;
  1788.   Dimension     h = 0;
  1789.   Dimension  hpad = CONTEXT_DATA (context)->sb_w;
  1790.   Dimension  vpad = CONTEXT_DATA (context)->sb_h;
  1791.   
  1792.   if (context->is_grid_cell) {
  1793.     Position    sx, sy;
  1794.     
  1795.     XtVaGetValues (CONTEXT_DATA (context)->scrolled, 
  1796.            XmNwidth, &w, XmNheight, &h, 0);
  1797.     
  1798.     *width = w;
  1799.     *height = h;
  1800.     
  1801.     XtVaGetValues (CONTEXT_DATA (context)->vscroll, XmNx, &sx, 0);
  1802.     XtVaGetValues (CONTEXT_DATA (context)->hscroll, XmNy, &sy, 0);
  1803.     
  1804.     if ((long) sx < (long) w)
  1805.       *width = (int32)w;
  1806.     else
  1807.       *width = (int32)(w + vpad);
  1808.     
  1809.     if ((long) sy < (long) h) 
  1810.       *height = (int32)h;
  1811.     else
  1812.       *height = (int32)(h + hpad);
  1813.     
  1814.     XtVaSetValues (CONTEXT_DATA (context)->scrolled, 
  1815.            XmNwidth, *width, XmNheight, *height, 0);
  1816.     }
  1817.   else {
  1818.     Widget dap = XtParent( CONTEXT_DATA (context)->drawing_area );
  1819.     
  1820.     XtVaGetValues (dap, XmNwidth, &w, XmNheight, &h, 0);
  1821.     *width = (int32) w;
  1822.     *height = (int32) h;
  1823.  
  1824.     XtVaSetValues (CONTEXT_DATA (context)->drawing_area, 
  1825.            XmNwidth, *width, XmNheight, *height, 0);
  1826.   }
  1827. }
  1828.  
  1829. void
  1830. fe_GetMargin(MWContext *context, int32 *marginw_ptr, int32 *marginh_ptr)
  1831. {
  1832.   int32 w, h;
  1833.   if (context->is_grid_cell) {
  1834.     w = FEUNITS_X(7, context);
  1835.     h = FEUNITS_X(4, context);
  1836.   } else if (context->type == MWContextMail ||
  1837.          context->type == MWContextNews) {
  1838.     w = FEUNITS_X(8, context);
  1839.     h = 0; /* No top margin for mail and news windows */
  1840.   } else {
  1841.     w = FEUNITS_X(8, context);
  1842.     h = FEUNITS_X(8, context);
  1843.   }
  1844.  
  1845.   if (marginw_ptr) *marginw_ptr = w;
  1846.   if (marginh_ptr) *marginh_ptr = h;
  1847. }
  1848.  
  1849.  
  1850. void
  1851. XFE_LayoutNewDocument (MWContext *context, URL_Struct *url,
  1852.               int32 *iWidth, int32 *iHeight,
  1853.                int32 *mWidth, int32 *mHeight)
  1854. {
  1855.   Dimension w = 0, h = 0;
  1856.   XColor color;
  1857.   int32 fe_mWidth, fe_mHeight;
  1858.   Boolean grid_cell_p = context->is_grid_cell;
  1859.  
  1860.   /* Fix for bug #29631 */
  1861.   if (context == last_documented_xref_context)
  1862.         {
  1863.                 last_documented_xref_context = 0;
  1864.                 last_documented_xref = 0;
  1865.                 last_documented_anchor_data = 0;
  1866.         }
  1867.  
  1868.   fe_FreeTransientColors(context);
  1869.   
  1870.   CONTEXT_DATA (context)->delayed_images_p = False;
  1871.  
  1872.   color.pixel = CONTEXT_DATA (context)->default_bg_pixel;
  1873.   fe_QueryColor (context, &color);
  1874.  
  1875.   /* The pixmap itself is freed when its IL_Image is destroyed. */
  1876.   CONTEXT_DATA (context)->backdrop_pixmap = 0;
  1877.  
  1878.   /* Set background after making the backdrop_pixmap 0 as SetBackground
  1879.    * will ignore a background setting request if backdrop_pixmap is
  1880.    * available.
  1881.    */
  1882.   XFE_SetBackgroundColor (context,
  1883.               color.red >> 8,
  1884.               color.green >> 8,
  1885.               color.blue >> 8);
  1886.  
  1887.   if (grid_cell_p) {
  1888.     if (!CONTEXT_DATA (context)->drawing_area) return;
  1889.  
  1890.     XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  1891.                XmNwidth, &w, XmNheight, &h, 0);
  1892.   } else {
  1893.     if (!CONTEXT_DATA (context)->scrolled) return;
  1894.  
  1895.     XtVaGetValues (CONTEXT_DATA (context)->scrolled,
  1896.          XmNwidth, &w, XmNheight, &h, 0);
  1897.   }
  1898.   if (!w || !h) abort ();
  1899.  
  1900.   /* Clear the background since, in the case of grid cells without borders, 
  1901.      the grid boundaries don't get cleared */
  1902.   XClearArea (XtDisplay (CONTEXT_WIDGET (context)),
  1903.           XtWindow (CONTEXT_DATA (context)->drawing_area), 
  1904.           0, 0,
  1905.           CONTEXT_DATA (context)->scrolled_width,
  1906.           CONTEXT_DATA (context)->scrolled_height, 
  1907.           False);
  1908.  
  1909.   /* Only make room for scrollbar if is non-grid cell,
  1910.    * or is grid cell but scrolling is turned on.  -slamm 
  1911.    */
  1912.   if (!context->is_grid_cell || CONTEXT_DATA(context)->grid_scrolling) {
  1913.   /* Subtract out the size of the scrollbars - they might not end up being
  1914.      present, but tell layout that all it has to work with is the area that
  1915.      would be available if there *were* scrollbars. */
  1916.     w -= CONTEXT_DATA (context)->sb_w;
  1917.     h -= CONTEXT_DATA (context)->sb_h;
  1918.   }
  1919.  
  1920.   w -= 2;    /* No, this isn't a hack.  What makes you think that? */
  1921.  
  1922.   *iWidth = w;
  1923.   *iHeight = h;
  1924.  
  1925.   fe_GetMargin(context, &fe_mWidth, &fe_mHeight);
  1926.  
  1927.   /*
  1928.    * If layout already knows margin width, let it pass unless it
  1929.    * is just too big.
  1930.    */
  1931.   if (*mWidth != 0)
  1932.     {
  1933.       if (*mWidth > ((w / 2) - 1))
  1934.         *mWidth = ((w / 2) - 1);
  1935.     }
  1936.   else
  1937.     {
  1938.       *mWidth = fe_mWidth;
  1939.     }
  1940.  
  1941.   /*
  1942.    * If layout already knows margin height, let it pass unless it
  1943.    * is just too big.
  1944.    */
  1945.   if (*mHeight != 0)
  1946.     {
  1947.       if (*mHeight > ((h / 2) - 1))
  1948.         *mHeight = ((h / 2) - 1);
  1949.     }
  1950.   else
  1951.     {
  1952.       *mHeight = fe_mHeight;
  1953.     }
  1954.  
  1955.   /* Get rid of the old title; don't install "Unknown" until we've gotten
  1956.      to the end of the document without XFE_SetDocTitle() having been called.
  1957.    */
  1958.   if (context->title)
  1959.     free (context->title);
  1960.   context->title = 0;
  1961.  
  1962.   if (!grid_cell_p && !CONTEXT_DATA (context)->is_resizing)
  1963.     fe_SetURLString (context, url);
  1964.  
  1965.   /* This is set in fe_resize_cb */
  1966.   CONTEXT_DATA (context)->is_resizing = FALSE;
  1967.  
  1968.   if (url->address && !(sploosh && !strcmp (url->address, sploosh)))
  1969.     {
  1970.       if (sploosh)
  1971.     {
  1972.       free (sploosh);
  1973.       sploosh = 0;
  1974.     }
  1975.       
  1976.       SHIST_AddDocument (context, SHIST_CreateHistoryEntry (url, ""));
  1977.     }
  1978.  
  1979.   /* Make sure we clear the string from the previous document */
  1980.   if (context->defaultStatus) {
  1981.     XP_FREE (context->defaultStatus);
  1982.     context->defaultStatus = 0;
  1983.   }
  1984.  
  1985.   /* #### temporary, until we support printing GIFs that don't have HTML
  1986.      wrapped around them. */
  1987. #if 0
  1988.   if (CONTEXT_DATA (context)->print_menuitem)
  1989.     XtVaSetValues (CONTEXT_DATA (context)->print_menuitem,
  1990.            XmNsensitive, !url->is_binary, 0);
  1991.   if (CONTEXT_DATA (context)->print_button)
  1992.     XtVaSetValues (CONTEXT_DATA (context)->print_button,
  1993.            XmNsensitive, !url->is_binary, 0);
  1994. #endif
  1995.  
  1996. #ifdef LEDGES
  1997.   XFE_ClearView (context, FE_TLEDGE);
  1998.   XFE_ClearView (context, FE_BLEDGE);
  1999. #endif
  2000.   fe_SetDocPosition (context, 0, 0);
  2001.  
  2002.   fe_FindReset (context);
  2003.   if (!grid_cell_p)
  2004.     fe_UpdateDocInfoDialog (context);
  2005. }
  2006.  
  2007.  
  2008. void
  2009. fe_FormatDocTitle (const char *title, const char *url, char *output, int size)
  2010. {
  2011.   if (size < 0) return;
  2012.  
  2013.   if (title && !XP_STRCASECMP(title, XP_GetString(XFE_UNTITLED)))
  2014.     title = 0;  /* Losers!!! */
  2015.  
  2016.   if (title)
  2017.     {
  2018.       XP_SAFE_SPRINTF (output, size, "%.200s", title);
  2019.     }
  2020.   else if (!url || 
  2021.            !*url || 
  2022.            strcmp(url,XP_GetString(XFE_LAY_LOCAL_FILE_URL_UNTITLED)) == 0)
  2023.     {
  2024.       XP_STRNCPY_SAFE(output, XP_GetString(XFE_UNTITLED), size);
  2025.     }
  2026.   else
  2027.     {
  2028.       const char *s = (const char *) strrchr (url, '/');
  2029.       if (s)
  2030.     s++;
  2031.       else
  2032.     s = url;
  2033.       PR_snprintf (output, size, "%.200s", s);
  2034.     }
  2035. }
  2036.  
  2037.  
  2038. void
  2039. XFE_SetDocTitle (MWContext *context, char *title)
  2040. {
  2041.   char buf [1024];
  2042.   char buf2 [1024];
  2043.   Widget shell = CONTEXT_WIDGET (context);
  2044.   XTextProperty text_prop;
  2045.   char *fmt;
  2046.   INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  2047.  
  2048.   if (context->type == MWContextSaveToDisk || !shell)
  2049.     return;
  2050.  
  2051.   /* For some context types like MWContextDialog, the shell is the parent
  2052.    * of the CONTEXT_WIDGET. In general, traverse back and get the shell.
  2053.    */
  2054.   while(!XtIsWMShell(shell) && (XtParent(shell)!=0))
  2055.     shell = XtParent(shell);
  2056.  
  2057.   /* We don't need to set the title for grid cells;
  2058.    * the backend sets the toplevel's title for us.
  2059.    */
  2060.   if (context->is_grid_cell)
  2061.     return;
  2062.  
  2063.   if (context->type == MWContextMessageComposition)
  2064.     {
  2065.       /* I18N watch */
  2066.       if (context->title) free (context->title);
  2067.       context->title = (title ? strdup (title) : 0);
  2068.       if (!title)
  2069.     title = XP_GetString( XFE_NO_SUBJECT );
  2070.       PR_snprintf (buf, sizeof(buf), "%.200s", title);
  2071.     }
  2072.   else
  2073.     {
  2074.       History_entry *he = SHIST_GetCurrent (&context->hist);
  2075.       char *url = (he && he->address ? he->address : 0);
  2076.  
  2077.       SHIST_SetTitleOfCurrentDoc (&context->hist, title);
  2078.  
  2079.       fe_UpdateDocInfoDialog (context);
  2080.  
  2081.       if (context->title) free (context->title);
  2082.       context->title = (title ? strdup (title) : 0);
  2083.  
  2084. #ifdef EDITOR
  2085.         /*
  2086.          *    For the editor we would rather at least have the filename,
  2087.          *    not so for Browser where it may be intentional.
  2088.          */
  2089.         if (context->type == MWContextEditor) {
  2090.             if (title == NULL || (title != NULL && title[0] == '\0'))
  2091.                 title = url;
  2092.         }
  2093. #endif /*EDITOR*/
  2094.  
  2095.         fe_FormatDocTitle (title, url, buf, sizeof(buf));
  2096.     }
  2097.  
  2098.   switch (context->type) {
  2099.     case MWContextAddressBook:
  2100.     case MWContextBookmarks:
  2101.     case MWContextHistory:
  2102.       fmt = "%s";
  2103.       break;
  2104.     case MWContextMail:
  2105.         /* Don't reset the title on the folders window */
  2106.         if (shell && !strcmp(XtName(shell), "MailFolder"))
  2107.       return;
  2108.     fmt = XP_GetString(XFE_MAIL_TITLE_FMT);
  2109.     break;
  2110.     case MWContextNews:
  2111.     fmt = XP_GetString(XFE_NEWS_TITLE_FMT);
  2112.     break;
  2113.     case MWContextMessageComposition:
  2114.         fmt = XP_GetString(XFE_COMPOSE);
  2115.     break;
  2116.     case MWContextEditor:
  2117.     fmt = XP_GetString(XFE_EDITOR_TITLE_FMT);
  2118.     break;
  2119.     case MWContextBrowser:     /* FALL THROUGH */
  2120.     default:
  2121.     fmt = XP_GetString(XFE_TITLE_FMT);
  2122.   }
  2123.   XP_SAFE_SPRINTF(buf2, sizeof (buf2), fmt, buf);
  2124.  
  2125.   /* For some context types like MWContextDialog, the shell is the parent
  2126.    * of the CONTEXT_WIDGET. In general, traverse back and get the shell.
  2127.    */
  2128.   while(!XtIsWMShell(shell) && (XtParent(shell)!=0))
  2129.     shell = XtParent(shell);
  2130.  
  2131.   if (INTL_GetCSIWinCSID(c) == CS_LATIN1)
  2132.     {
  2133.       text_prop.value = (unsigned char *) buf2;
  2134.       text_prop.encoding = XA_STRING;
  2135.       text_prop.format = 8;
  2136.       text_prop.nitems = strlen(buf2);
  2137.     }
  2138.   else
  2139.     {
  2140.       char *loc;
  2141.       int status;
  2142.  
  2143.       loc = (char *) fe_ConvertToLocaleEncoding(INTL_GetCSIWinCSID(c),
  2144.                                                 (unsigned char *) buf2);
  2145.       status = XmbTextListToTextProperty(XtDisplay(shell), &loc, 1,
  2146.                                          XStdICCTextStyle, &text_prop);
  2147.       if (loc != buf2)
  2148.         {
  2149.           XP_FREE(loc);
  2150.         }
  2151.       if (status != Success)
  2152.         {
  2153.           text_prop.value = (unsigned char *) buf2;
  2154.           text_prop.encoding = XA_STRING;
  2155.           text_prop.format = 8;
  2156.           text_prop.nitems = strlen(buf2);
  2157.         }
  2158.     }
  2159.  
  2160.    /* We should not call XSetWMName here because the shell might not
  2161.       be realized yet. You are going to get NULL window id when shell
  2162.       is not realized. Then, we will get X Error (Bad Window) with
  2163.       ChangeProperty error id.
  2164.  
  2165.       To fix this, we should use XtSetValues on both
  2166.       titleEncoding and title. And, when shell is realized, it will
  2167.       turn around, and change the window property (ie Calling
  2168.       XSetWMName) at the right time.
  2169.  
  2170.      I really don't know why they say that SetValues
  2171.      does not work for high-bit characters earlier. 
  2172.  
  2173.      Here, I set the titleEncoding too. I think that the hight-bit
  2174.      character problem should not exist now once we set the encoding.
  2175.  
  2176.      If I was proven to be wrong, please let me know - dh */
  2177.    XtVaSetValues (shell, XtNtitleEncoding, text_prop.encoding, 0);
  2178.    XtVaSetValues (shell, XtNtitle, text_prop.value, 0);
  2179.  
  2180.     /* Only set the icon title on browser windows - not mail, news or
  2181.        download. */
  2182.   if (context->type == MWContextBrowser)
  2183.   {
  2184.    /* Same comments at the block for XtNtitle */
  2185.    XtVaSetValues (shell, XtNiconNameEncoding, text_prop.encoding, 0);
  2186.    XtVaSetValues (shell, XtNiconName, text_prop.value, 0);
  2187.   }
  2188. }
  2189.  
  2190.  
  2191. void
  2192. fe_DestroyLayoutData (MWContext *context)
  2193. {
  2194.   LO_DiscardDocument (context);
  2195.   free (CONTEXT_DATA (context)->color_data);
  2196. }
  2197.  
  2198. void
  2199. XFE_FinishedLayout (MWContext *context)
  2200. {
  2201.   /* Since our processing of XFE_SetDocDimension() may have been lazy,
  2202.      do it for real this time. */
  2203.   CONTEXT_DATA (context)->doc_size_last_update_time = 0;
  2204.   /* Update scrollbars using final dimensions. */
  2205.   fe_SetDocPosition(context, CONTEXT_DATA (context)->document_x,
  2206.                     CONTEXT_DATA (context)->document_y);
  2207. }
  2208.  
  2209.  
  2210. void
  2211. fe_ClearArea (MWContext *context, int x, int y, unsigned int w, unsigned int h)
  2212. {
  2213.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  2214.   Drawable drawable = fe_drawable->xdrawable;
  2215.   Display *dpy = fe_display;
  2216.   GC gc;
  2217.   XGCValues gcv;
  2218.  
  2219.   memset (&gcv, ~0, sizeof (gcv));
  2220.   gcv.foreground = CONTEXT_DATA (context)->bg_pixel;
  2221.   gc = fe_GetGCfromDW (dpy, drawable, (GCForeground), &gcv,
  2222.                        fe_drawable->clip_region);
  2223.  
  2224.   XFillRectangle (dpy, drawable, gc, x, y, w, h);
  2225. }
  2226.  
  2227. void
  2228. fe_ClearAreaWithColor (MWContext *context, int x, int y, unsigned int w,
  2229.                        unsigned int h, Pixel color)
  2230. {
  2231.   fe_Drawable *fe_drawable = CONTEXT_DATA (context)->drawable;
  2232.   Drawable drawable = fe_drawable->xdrawable;
  2233.   Display *dpy = fe_display;
  2234.   GC gc;
  2235.   XGCValues gcv;
  2236.  
  2237.   memset (&gcv, ~0, sizeof (gcv));
  2238.   gcv.foreground = color;
  2239.   gc = fe_GetGCfromDW (dpy, drawable, (GCForeground), &gcv,
  2240.                        fe_drawable->clip_region);
  2241.   XFillRectangle (dpy, drawable, gc, x, y, w, h);
  2242. }
  2243.  
  2244. void
  2245. XFE_ClearView (MWContext *context, int which)
  2246. {
  2247.   if (!XtIsManaged (CONTEXT_WIDGET (context)))
  2248.     return;
  2249.  
  2250.   /* Clear out the data for the mouse-highlighted item.
  2251.      #### What if one ledge is being cleared but not all, and the
  2252.      highlighted item is in the other?
  2253.    */
  2254.   last_armed_xref = 0;
  2255.   last_armed_xref_highlighted_p = False;
  2256.   last_documented_xref_context = 0;
  2257.   last_documented_xref = 0;
  2258.   last_documented_anchor_data = 0;
  2259.   fe_SetCursor (context, False);
  2260.  
  2261.   switch (which)
  2262.     {
  2263. #ifdef LEDGES
  2264.     case FE_TLEDGE:
  2265.       XClearWindow (XtDisplay (CONTEXT_WIDGET (context)),
  2266.             XtWindow (CONTEXT_DATA (context)->top_ledge));
  2267.       break;
  2268.     case FE_BLEDGE:
  2269.       XClearWindow (XtDisplay (CONTEXT_WIDGET (context)),
  2270.             XtWindow (CONTEXT_DATA (context)->bottom_ledge));
  2271.       break;
  2272. #endif
  2273.     case FE_VIEW:
  2274.       fe_ClearArea (context, 0, 0,
  2275.             /* Some random big number (but if it's too big,
  2276.                like most-possible-short, it will make some
  2277.                MIT R4 servers mallog excessively, sigh.) */
  2278.             CONTEXT_WIDGET (context)->core.width * 2,
  2279.             CONTEXT_WIDGET (context)->core.height * 2);
  2280.       break;
  2281.     default:
  2282.       abort ();
  2283.     }
  2284. }
  2285.  
  2286. void
  2287. XFE_BeginPreSection (MWContext *context)
  2288. {
  2289. }
  2290.  
  2291. void
  2292. XFE_EndPreSection (MWContext *context)
  2293. {
  2294. }
  2295.  
  2296. void
  2297. XFE_FreeEdgeElement (MWContext *context, LO_EdgeStruct *edge)
  2298. {
  2299.   SashInfo *sashinfo = edge->FE_Data;
  2300.  
  2301.   if (!sashinfo) return;
  2302.  
  2303.   if (sashinfo->sash) {
  2304.     XtRemoveCallback (sashinfo->sash, XtNdestroyCallback,
  2305.               fe_sash_destroy_cb, (XtPointer) sashinfo);
  2306.     XtDestroyWidget (sashinfo->sash);
  2307.     sashinfo->sash = NULL;
  2308.   }
  2309.  
  2310.   edge->FE_Data = NULL;
  2311.   XP_FREE (sashinfo);
  2312. }
  2313.  
  2314. /*
  2315.  * This is called by the plugin code to create a new embedded window
  2316.  * for the plugin in the specified context.
  2317.  */
  2318. void
  2319. XFE_CreateEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  2320. {
  2321.     Widget parent = CONTEXT_DATA (context)->drawing_area;
  2322.     LO_EmbedStruct* lo_struct;
  2323.     Widget embed;
  2324.     Window win;
  2325.     int xp, yp;
  2326.     int32 xs, ys;
  2327.  
  2328.     /* now we have a live embed and its the first time so we need to
  2329.        prepare a window for it */
  2330.     if (XP_FAIL_ASSERT(app->np_data != NULL))
  2331.         return;
  2332.  
  2333.     lo_struct = ((np_data *) app->np_data)->lo_struct;
  2334.     if (XP_FAIL_ASSERT(lo_struct != NULL))
  2335.         return;
  2336.  
  2337.     xp = lo_struct->x;
  2338.     yp = lo_struct->y;
  2339.     xs = lo_struct->width;
  2340.     ys = lo_struct->height;
  2341.     
  2342.     if (CONTEXT_DATA(context)->is_fullpage_plugin) {
  2343.         /* This is a full page plugin */
  2344.         int32 mWidth, mHeight;
  2345.  
  2346.         FE_GetFullWindowSize(context, &xs, &ys);
  2347.         fe_GetMargin(context, &mWidth, &mHeight);
  2348.         xs -= mWidth;
  2349.         ys -= mHeight;
  2350.         
  2351.         xp = yp = 0;
  2352.     }
  2353.  
  2354.     {
  2355.         Pixel bg;
  2356.         Arg av[20];
  2357.         int ac = 0;
  2358.  
  2359.         XtVaGetValues(parent, XmNbackground, &bg, 0);
  2360.  
  2361.         /* XtSetArg(av[ac], XmNborderWidth, 1);         ac++ */
  2362.         XtSetArg(av[ac], XmNx, (Position)xp);           ac++;
  2363.         XtSetArg(av[ac], XmNy, (Position)yp);           ac++;
  2364.         XtSetArg(av[ac], XmNwidth, (Dimension)xs);      ac++;
  2365.         XtSetArg(av[ac], XmNheight, (Dimension)ys);     ac++;
  2366. #ifdef X_PLUGINS
  2367.         XtSetArg(av[ac], XmNmarginWidth, 0);            ac++;
  2368.         XtSetArg(av[ac], XmNmarginHeight, 0);           ac++;
  2369. #endif
  2370.         XtSetArg(av[ac], XmNbackground, bg);            ac++;
  2371.         embed = XmCreateDrawingArea(parent, "netscapeEmbed", av, ac);
  2372.     }
  2373.  
  2374.     XtRealizeWidget (embed); /* create window, but don't map */
  2375.     win = XtWindow(embed);
  2376.  
  2377.     if (fe_globalData.fe_guffaw_scroll == 1) {
  2378.         XSetWindowAttributes attr;
  2379.         unsigned long valuemask;
  2380.  
  2381.         valuemask = CWBitGravity | CWWinGravity;
  2382.         attr.win_gravity = StaticGravity;
  2383.         attr.bit_gravity = StaticGravity;
  2384.         XChangeWindowAttributes(XtDisplay (embed), XtWindow (embed),
  2385.                                 valuemask, &attr);
  2386.     }
  2387.     /* XtManageChild (embed); */
  2388.  
  2389.     /* make a plugin wininfo */
  2390.     {
  2391.         NPWindow *nWin = (NPWindow *)malloc(sizeof(NPWindow));
  2392.         if(nWin) {
  2393. #ifdef X_PLUGINS
  2394.             NPSetWindowCallbackStruct *fe_data;
  2395. #endif /* X_PLUGINS */
  2396.  
  2397.             nWin->window = (void *)win;
  2398.             nWin->x = xp;
  2399.             nWin->y = yp;
  2400.             nWin->width = xs;
  2401.             nWin->height = ys;
  2402.             nWin->type = NPWindowTypeWindow;
  2403.         
  2404. #ifdef X_PLUGINS
  2405.             fe_data = (NPSetWindowCallbackStruct *)
  2406.                 malloc(sizeof(NPSetWindowCallbackStruct));
  2407.  
  2408.             if (fe_data) {
  2409.                 Visual *v = 0;
  2410.                 Colormap cmap = 0;
  2411.                 Cardinal depth = 0;
  2412.  
  2413.                 XtVaGetValues(CONTEXT_WIDGET(context), XtNvisual, &v,
  2414.                               XtNcolormap, &cmap, XtNdepth, &depth, 0);
  2415.  
  2416.                 fe_data->type = NP_SETWINDOW;
  2417.                 fe_data->display = (void *) XtDisplay(embed);
  2418.                 fe_data->visual = v;
  2419.                 fe_data->colormap = cmap;
  2420.                 fe_data->depth = depth;
  2421.                 nWin->ws_info = (void *) fe_data;
  2422.             }
  2423. #endif /* X_PLUGINS */
  2424.         }
  2425.         app->wdata = nWin;
  2426.         app->fe_data = (void *)embed;
  2427.     }
  2428. }
  2429.  
  2430. /*
  2431.  * This is called by the plugin code to save an embed window in a
  2432.  * "safe place" (i.e., where it won't get destroyed when the context
  2433.  * goes away. It is called in response to NPL_DeleteEmbed().
  2434.  */
  2435. void
  2436. XFE_SaveEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  2437. {
  2438.     Widget embedWidget;
  2439.     MWContext *safeContext;
  2440.     Widget safeWidget;
  2441.     Widget parentWidget;
  2442.  
  2443.     if (XP_FAIL_ASSERT(app->fe_data != NULL))
  2444.         return;
  2445.  
  2446.     embedWidget = (Widget) app->fe_data;
  2447.     if (XP_FAIL_ASSERT(XtIsWidget(embedWidget)))
  2448.         return;
  2449.  
  2450.     XUnmapWindow(XtDisplay(embedWidget), XtWindow(embedWidget));
  2451.  
  2452.     safeContext = XP_GetNonGridContext(context);
  2453.     if (XP_FAIL_ASSERT(safeContext != NULL))
  2454.         return;
  2455.  
  2456.     safeWidget = CONTEXT_DATA(safeContext)->drawing_area;
  2457.     if (XP_FAIL_ASSERT(safeWidget != NULL &&
  2458.                        XtIsWidget(safeWidget) &&
  2459.                        XtIsComposite(safeWidget)))
  2460.         return;
  2461.             
  2462.     parentWidget = XtParent(embedWidget);
  2463.  
  2464.     if (safeWidget != parentWidget) {
  2465.         /* If the safe widget and the parent widget are not one in the
  2466.            same, then we have a situation where the embedded object is
  2467.            on a grid context. Reparent the embedded object's widget to
  2468.            the safe context. First, we'll remove it from the current
  2469.            context... */
  2470.         if (XP_OK_ASSERT(parentWidget != NULL && XtIsComposite(parentWidget))) {
  2471.             CompositeWidgetClass c;
  2472.             c = (CompositeWidgetClass) XtClass(parentWidget);
  2473.             (c->composite_class.delete_child)(embedWidget);
  2474.         }
  2475.  
  2476.         /* Then, reparent it to the safe widget; both at the X and Xt
  2477.            levels. */
  2478.         XtParent(embedWidget) = safeWidget;
  2479.  
  2480.         {
  2481.             CompositeWidgetClass c;
  2482.             c = (CompositeWidgetClass) XtClass(safeWidget);
  2483.             (c->composite_class.insert_child)(embedWidget);
  2484.         }
  2485.  
  2486.         XReparentWindow(XtDisplay(embedWidget), XtWindow(embedWidget),
  2487.                         XtWindow(safeWidget), 0, 0);
  2488.     }
  2489. }
  2490.  
  2491. /*
  2492.  * This is called by the plugin code to restore a previously "saved"
  2493.  * embedded window to the new context.
  2494.  */
  2495. void
  2496. XFE_RestoreEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  2497. {
  2498.     Widget embedWidget;
  2499.     Widget safeWidget;
  2500.  
  2501.     if (XP_FAIL_ASSERT(app != NULL && app->fe_data != NULL))
  2502.         return;
  2503.  
  2504.     embedWidget = (Widget) app->fe_data;
  2505.     if (XP_FAIL_ASSERT(XtIsWidget(embedWidget)))
  2506.         return;
  2507.  
  2508.     if (XtParent(embedWidget) != CONTEXT_DATA(context)->drawing_area) {
  2509.         /* Reparent the embedded object's widget from the safe context
  2510.            to the current context. */
  2511.         Widget safeWidget = XtParent(embedWidget);
  2512.         Widget parentWidget = CONTEXT_DATA(context)->drawing_area;
  2513.  
  2514.         /* Start by reparenting it at the X level */
  2515.         {
  2516.             int xp = 0;
  2517.             int yp = 0;
  2518.  
  2519.             if (app->np_data) {
  2520.                 LO_EmbedStruct* embed_struct
  2521.                     = ((np_data*) app->np_data)->lo_struct;
  2522.  
  2523.                 if (embed_struct) {
  2524.                     xp = embed_struct->x + embed_struct->x_offset -
  2525.                         CONTEXT_DATA(context)->document_x;
  2526.                     yp = embed_struct->y + embed_struct->y_offset -
  2527.                         CONTEXT_DATA(context)->document_y;
  2528.                 }
  2529.             }
  2530.  
  2531.             XReparentWindow(XtDisplay(embedWidget), XtWindow(embedWidget),
  2532.                             XtWindow(parentWidget), xp, yp);
  2533.         }
  2534.  
  2535.         /* Now remove it from the safe context. Check to make sure we
  2536.            can really do composite ops on this thing... */
  2537.         if (XP_OK_ASSERT(safeWidget != NULL && XtIsComposite(safeWidget))) {
  2538.             CompositeWidgetClass c;
  2539.             c = (CompositeWidgetClass) XtClass(safeWidget);
  2540.             (c->composite_class.delete_child)(embedWidget);
  2541.         }
  2542.  
  2543.         /* Now reparent it to the current context */
  2544.         XtParent(embedWidget) = parentWidget;
  2545.  
  2546.         /* Again, a sanity check... */
  2547.         if (XP_OK_ASSERT(parentWidget != NULL && XtIsComposite(parentWidget))) {
  2548.             CompositeWidgetClass c;
  2549.             c = (CompositeWidgetClass) XtClass(parentWidget);
  2550.             (c->composite_class.insert_child)(embedWidget);
  2551.         }
  2552.     }
  2553.  
  2554.     XtMapWidget(embedWidget);
  2555. }
  2556.  
  2557. /*
  2558.  * This is called by the plugin code to destroy the embedded window.
  2559.  * It is either called _immediately_ in response to NPL_DeleteEmbed(),
  2560.  * or via layout when a saved embed window is released from the
  2561.  * history.
  2562.  */
  2563. void
  2564. XFE_DestroyEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  2565. {
  2566.     if (app) {
  2567.         NPWindow* nWin = app->wdata;
  2568.         Widget embed_widget = (Widget)app->fe_data;
  2569.  
  2570.         if (embed_widget)
  2571.             XtDestroyWidget(embed_widget);
  2572.  
  2573.         if (nWin) {
  2574.             if (nWin->ws_info)
  2575.                 free(nWin->ws_info);
  2576.  
  2577.             free(nWin);
  2578.         }
  2579.     }
  2580.  
  2581.     /* Reset fullpage plugin */
  2582.     CONTEXT_DATA(context)->is_fullpage_plugin = 0;
  2583. }
  2584.  
  2585. void
  2586. XFE_FreeEmbedElement (MWContext *context, LO_EmbedStruct *embed_struct)
  2587. {
  2588.     NPL_EmbedDelete(context, embed_struct);
  2589. }
  2590.  
  2591. #ifdef SHACK
  2592. extern void fe_showRDFView (Widget w, int width, int height);
  2593. #endif /* SHACK */
  2594.  
  2595. void
  2596. XFE_DisplayEmbed (MWContext *context,
  2597.           int iLocation, LO_EmbedStruct *embed_struct)
  2598. {
  2599.     NPEmbeddedApp *eApp;
  2600.     int32 xs, ys;
  2601.  
  2602.     if (!embed_struct) return;
  2603.     eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
  2604.     if (!eApp) return;
  2605.  
  2606.     /* Shouldn't be here if HIDDEN */
  2607.     if (embed_struct->ele_attrmask & LO_ELE_HIDDEN) 
  2608.       return;
  2609.     
  2610.  
  2611.     /* Layout might have changed the location of the embed since we
  2612.      * created the embed in XFE_GetEmbedSize()
  2613.      */
  2614.     xs = embed_struct->x + embed_struct->x_offset -
  2615.       CONTEXT_DATA (context)->document_x;
  2616.     ys = embed_struct->y + embed_struct->y_offset -
  2617.       CONTEXT_DATA (context)->document_y;
  2618.  
  2619.     /* If this is a full page plugin, then plugin needs to be notified of
  2620.        the new size as relayout never happens for this when we resize.
  2621.        Our resize handler marks this context as a fullpage plugin. */
  2622.     
  2623.     if (CONTEXT_DATA(context)->is_fullpage_plugin) {
  2624.     NPWindow *nWin = (NPWindow *)eApp->wdata;
  2625.  
  2626.     FE_GetFullWindowSize(context, &xs, &ys);
  2627.     
  2628. #if 0
  2629.     int32 mWidth, mHeight;
  2630.     /* Normally the right thing to do is to subtract the margin width.
  2631.      * But we wont do this and give the plugin the full html area.
  2632.      * Remember, layout still thinks the we offset the fullpage plugin
  2633.      * by the margin offset.
  2634.      */
  2635.     fe_GetMargin(context, &mWidth, &mHeight);
  2636.     xs -= mWidth;
  2637.     ys -= mHeight;
  2638. #else /* 0 */
  2639.     /* In following suit with our hack of no margins for fullpage plugins
  2640.      * we force the plugin to (0,0) position.
  2641.      */
  2642.     XtVaSetValues((Widget)eApp->fe_data, XmNx, (Position)0,
  2643.               XmNy, (Position)0, 0);
  2644. #endif /* 0 */
  2645.  
  2646.     if (nWin->width != xs || nWin->height != ys) {
  2647.         nWin->width = xs;
  2648.         nWin->height = ys;
  2649.         (void)NPL_EmbedSize(eApp);
  2650.     }
  2651.     }
  2652.     else {
  2653.     /* The layer containing the plugin may be hidden or clipped by
  2654.        an enclosing layer, in which case we should unmap the
  2655.        plugin's window */
  2656.     XtSetMappedWhenManaged((Widget)eApp->fe_data,
  2657.                    !(embed_struct->ele_attrmask &LO_ELE_INVISIBLE));
  2658.  
  2659.     /* The location of the plugin may have changed since it was
  2660.      * created, either at the behest of Layout or due to movement
  2661.      * of an enclosing layer.  So, change the position of the
  2662.      * plugin. Do this only if we are not a fullpage plugin as
  2663.      * fullpage plugins are always at (0,0).  */
  2664.  
  2665.     /* but first, update the size and call a set window... */
  2666.     (void)NPL_EmbedSize(eApp);
  2667.  
  2668.     XtVaSetValues((Widget)eApp->fe_data, XmNx, (Position)xs,
  2669.               XmNy, (Position)ys, 0);
  2670.     }
  2671.  
  2672.     /* Manage the embed window. XFE_GetEmbedSize() only creates the it. */
  2673.     if (!XtIsManaged((Widget)eApp->fe_data))
  2674.     XtManageChild((Widget)eApp->fe_data);
  2675.  
  2676. #ifdef SHACK
  2677.     /* ... and now for the SHACK stuff */
  2678.     {
  2679.         NPWindow *nWin = (NPWindow *) eApp->wdata;
  2680.         int width = nWin->width;
  2681.            int height = nWin->height;
  2682.            Widget w = (Widget) eApp->fe_data;
  2683.  
  2684.         fe_showRDFView (w, width, height);
  2685.     }
  2686. #endif /* SHACK */
  2687. }
  2688.  
  2689. void
  2690. XFE_GetEmbedSize (MWContext *context, LO_EmbedStruct *embed_struct,
  2691.           NET_ReloadMethod force_reload)
  2692. {
  2693.     NPEmbeddedApp *eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
  2694.     int32 doc_id;
  2695.     lo_TopState *top_state;
  2696.  
  2697.     /* here we need only decrement the number of embeds expected to load */
  2698.     doc_id = XP_DOCID(context);
  2699.     top_state = lo_FetchTopState(doc_id);
  2700.  
  2701.     if(!eApp)
  2702.     {
  2703.     /* Determine if this is a fullpage plugin. Do this _now_ so
  2704.            that it'll be available when NPL_EmbedCreate() calls back
  2705.            to XFE_CreateEmbedWindow() */
  2706.     if((embed_struct->width == 1) &&
  2707.            (embed_struct->height == 1) &&
  2708.            (embed_struct->attribute_cnt > 0) &&
  2709.            (!strcmp(embed_struct->attribute_list[0], "src")) &&
  2710.            (!strcmp(embed_struct->value_list[0], "internal-external-plugin"))) {
  2711.             CONTEXT_DATA(context)->is_fullpage_plugin = 1;
  2712.         }
  2713.  
  2714.     /* attempt to make a plugin */
  2715. #ifdef UNIX_EMBED
  2716.     if(!(eApp = NPL_EmbedCreate(context, embed_struct)))
  2717. #else
  2718.     if(1)  /* disable unix plugin's */
  2719. #endif
  2720.     {
  2721.         /* hmm, that failed which is unusual */
  2722.         embed_struct->width = embed_struct->height=1;
  2723.         return;
  2724.     }
  2725.     eApp->type = NP_Plugin;
  2726.  
  2727.     if (embed_struct->ele_attrmask & LO_ELE_HIDDEN) {
  2728.         /* Hidden plugin. Dont create window for it. */
  2729.         eApp->fe_data = 0;
  2730.         eApp->wdata = 0;
  2731.         embed_struct->width = embed_struct->height=0;
  2732.         /* --- begin fix for bug# 35087 --- */
  2733.         embed_struct->FE_Data = (void *)eApp;
  2734.  
  2735.             if (NPL_EmbedStart(context, embed_struct, eApp) != NPERR_NO_ERROR) {
  2736.             /* Spoil sport! */
  2737.                 /* XXX This used to be a call to fe_destroyEmbed,
  2738.                    which has now been massaged into a front-end
  2739.                    callback. However, it doesn't (and didn't!) _do_
  2740.                    anything unless eApp->fe_data or eApp->wdata
  2741.                    contain something, and we've just hard-coded them
  2742.                    to zero!
  2743.  
  2744.                 XFE_DestroyEmbedWindow(context, eApp) */
  2745.                 embed_struct->FE_Data = NULL;
  2746.             return;
  2747.         }
  2748.         /* --- end fix for bug# 35087 --- */
  2749.  
  2750.             /* XXX NPL_EmbedSize does nothing if eApp->wdata == NULL;
  2751.                makes sense because this thing is _hidden_.
  2752.  
  2753.             (void)NPL_EmbedSize(eApp); */
  2754.         return;
  2755.     }
  2756.  
  2757.     if (NPL_EmbedStart(context, embed_struct, eApp) != NPERR_NO_ERROR) {
  2758.         /* Spoil sport! */
  2759.         XFE_DestroyEmbedWindow(context, eApp);
  2760.             embed_struct->FE_Data = NULL;
  2761.         return;
  2762.     }
  2763.     }
  2764.  
  2765.     /* always inform plugins of size changes */
  2766.     (void)NPL_EmbedSize(eApp);
  2767. }
  2768.  
  2769. /*************************************************************************
  2770.  * Java Stuff
  2771.  ************************************************************************/
  2772.  
  2773. #ifdef JAVA
  2774. static void* PR_CALLBACK 
  2775. FE_GetAwtWindow(MWContext *context, LJAppletData* ad)
  2776. {
  2777.     return ad->fe_data;
  2778. }
  2779. #endif
  2780.  
  2781. #ifdef JAVA
  2782. static void PR_CALLBACK
  2783. FE_SaveJavaWindow(MWContext *context, LJAppletData* ad, void* window)
  2784. {
  2785.     Widget * kids;
  2786.     Cardinal nkids = 0;
  2787.     Widget contextWidget = (Widget)window;
  2788.     XtUnmapWidget(contextWidget);  
  2789.      
  2790.     /*
  2791.     ** We are about to destroy contextWidget, but we want to hang on
  2792.     ** to its child, so that we can remap it when the applet's page
  2793.     ** is browsed again. We reparent the child to mozilla's main 
  2794.     ** drawing area since we know that it will be there as long as
  2795.     ** mozilla is there. We do the reparenting at both X and Xt level.
  2796.     */
  2797.     
  2798.     XtVaGetValues(contextWidget, XmNchildren, &kids,
  2799.           XmNnumChildren, &nkids, NULL);
  2800.     /* XP_ASSERT(nkids == 1);  */
  2801.  
  2802.     if (nkids >= 1) {
  2803.     Widget kid;
  2804.  
  2805.     kid = kids[0];
  2806.     (((CompositeWidgetClass) contextWidget->core.widget_class)->
  2807.      composite_class.delete_child)(kid);
  2808.     kid->core.parent = CONTEXT_DATA(ad->context)->drawing_area; 
  2809.  
  2810.     (((CompositeWidgetClass) XtParent(kid)->core.widget_class)->
  2811.      composite_class.insert_child)(kid);
  2812.  
  2813.     XUnmapWindow(XtDisplay(kid), XtWindow(kid));
  2814.         XReparentWindow(XtDisplay(kid), XtWindow(kid),
  2815.             XtWindow(CONTEXT_DATA(ad->context)->drawing_area), 0, 0); 
  2816.     }
  2817.  
  2818.     /*
  2819.     ** Destroy the window and set the pointer to null because it will
  2820.     ** need to get recreated.
  2821.     */
  2822.     XtDestroyWidget(contextWidget); 
  2823.     ad->window = NULL; 
  2824. }
  2825. #endif
  2826.  
  2827. void
  2828. XFE_HideJavaAppElement(MWContext *context, struct LJAppletData* session_data)
  2829. {
  2830. #ifdef JAVA
  2831.     LJ_HideJavaAppElement(context, session_data, FE_SaveJavaWindow);
  2832. #endif /* JAVA */
  2833. }
  2834.  
  2835. static void PR_CALLBACK
  2836. FE_FreeJavaWindow(MWContext *context, struct LJAppletData *appletData,
  2837.           void* window)
  2838. {
  2839.     Widget contextWidget = (Widget)window;
  2840.     XtDestroyWidget(contextWidget);
  2841. }
  2842.  
  2843. void
  2844. XFE_FreeJavaAppElement(MWContext *context, struct LJAppletData *appletData)
  2845. {
  2846. #ifdef JAVA
  2847.     LJ_FreeJavaAppElement(context, appletData, 
  2848.               FE_SaveJavaWindow,
  2849.               FE_FreeJavaWindow);
  2850. #endif /* JAVA */
  2851. }
  2852.  
  2853.  
  2854. static void PR_CALLBACK 
  2855. FE_DisplayNoJavaIcon(MWContext *pContext, LO_JavaAppStruct *java_struct)
  2856. {
  2857.     /* write me */
  2858. }
  2859.  
  2860. #ifdef JAVA
  2861.  
  2862. static void* PR_CALLBACK 
  2863. FE_CreateJavaWindow(MWContext *context, LO_JavaAppStruct *java_struct,
  2864.             int32 xp, int32 yp, int32 xs, int32 ys)
  2865. {
  2866.     LJAppletData* ad = (LJAppletData*)java_struct->session_data;
  2867.     Widget parent;
  2868.     Arg av[20];
  2869.     int ac = 0;
  2870.     Pixel bg;
  2871.     Widget contextWidget;
  2872.  
  2873.     parent = CONTEXT_DATA(context)->drawing_area;
  2874.  
  2875.     /* Adjust xp and yp for their offsets within the window */
  2876.     xp -= CONTEXT_DATA(context)->document_x;
  2877.     yp -= CONTEXT_DATA(context)->document_y;
  2878.     
  2879.     /*
  2880.     ** First time in for this applet; create motif widget for it
  2881.     */
  2882.     XtVaGetValues(parent, XmNbackground, &bg, 0);
  2883.     ac = 0;
  2884.     XtSetArg(av[ac], XmNborderWidth, 0); ac++;
  2885.     XtSetArg(av[ac], XmNx, (Position)xp); ac++;
  2886.     XtSetArg(av[ac], XmNy, (Position)yp); ac++;
  2887.     XtSetArg(av[ac], XmNwidth, (Dimension)xs); ac++;
  2888.     XtSetArg(av[ac], XmNheight, (Dimension)ys); ac++;
  2889.     XtSetArg(av[ac], XmNmarginWidth, 0); ac++;
  2890.     XtSetArg(av[ac], XmNmarginHeight, 0); ac++;
  2891.     XtSetArg(av[ac], XmNresizePolicy, XmRESIZE_NONE); ac++;
  2892.     XtSetArg(av[ac], XmNbackground, bg); ac++;
  2893. #ifdef DEBUG
  2894.     XtSetArg(av[ac], XmNtitle, ad->documentURL); ac++;
  2895. #endif /* DEBUG */
  2896.     contextWidget = XmCreateDrawingArea(parent,
  2897.                     (char *)java_struct->attr_name,/* XXX */
  2898.                     av, ac);
  2899.     XtSetMappedWhenManaged(contextWidget, FALSE);
  2900.     XtRealizeWidget(contextWidget); /* create window, but don't map */
  2901.  
  2902.     if (fe_globalData.fe_guffaw_scroll == 1)
  2903.     {
  2904.     XSetWindowAttributes attr;
  2905.     unsigned long valuemask;
  2906.     valuemask = CWBitGravity | CWWinGravity;
  2907.     attr.win_gravity = StaticGravity;
  2908.     attr.bit_gravity = StaticGravity;
  2909.     XChangeWindowAttributes(XtDisplay(contextWidget),
  2910.                 XtWindow(contextWidget),
  2911.                 valuemask, &attr);
  2912.     }
  2913.     XtManageChild(contextWidget);
  2914.     /* XSync(XtDisplay(contextWidget), 0); */
  2915.  
  2916.     return contextWidget;
  2917. }
  2918.  
  2919. static void PR_CALLBACK 
  2920. FE_RestoreJavaWindow(MWContext *context, LJAppletData* ad,
  2921.              int32 xp, int32 yp, int32 xs, int32 ys)
  2922. {
  2923.     /*
  2924.     ** If the user goes  to another page and comes back to the applet's 
  2925.     ** page, the applet needs to be shown, So reparent the applet to the
  2926.     ** embedParent, when we have to show it. We don't need the old 
  2927.     ** squirrelling away code anymore.
  2928.     */
  2929.  
  2930.     Widget kid            = ad->fe_data;
  2931.     Widget embedParent    = ad->window;
  2932.  
  2933.     if (kid == NULL) return;
  2934.     
  2935.     /* Adjust xp and yp for their offsets within the window */
  2936.     xp -= CONTEXT_DATA(context)->document_x;
  2937.     yp -= CONTEXT_DATA(context)->document_y;
  2938.     
  2939.     XReparentWindow(XtDisplay(kid), XtWindow(kid), XtWindow(embedParent), 0, 0);
  2940.     if (XtParent(kid) != embedParent) {
  2941.     /* Motif hackery */
  2942.     (((CompositeWidgetClass) XtParent(kid)->core.widget_class)-> composite_class.delete_child) (kid);
  2943.     kid->core.parent = embedParent;
  2944.     (((CompositeWidgetClass) embedParent->core.widget_class)->composite_class.insert_child) (kid);
  2945.     (((CompositeWidgetClass) embedParent->core.widget_class)-> composite_class.change_managed) (embedParent);
  2946.  
  2947.     }
  2948.     XtMapWidget(kid); 
  2949.         
  2950. }
  2951.  
  2952. static void PR_CALLBACK 
  2953. FE_SetJavaWindowPos(MWContext *context, void* window,
  2954.             int32 xp, int32 yp, int32 xs, int32 ys)
  2955. {
  2956.     /* Adjust xp and yp for their offsets within the window */
  2957.     xp -= CONTEXT_DATA(context)->document_x;
  2958.     yp -= CONTEXT_DATA(context)->document_y;
  2959.     
  2960.     XtVaSetValues((Widget)window,
  2961.           XmNx, (Position)xp,
  2962.           XmNy, (Position)yp, 0);
  2963. }
  2964.  
  2965. static void PR_CALLBACK 
  2966. FE_SetJavaWindowVisibility(MWContext *context, void* window, PRBool visible)
  2967. {
  2968.     /* The layer containing the applet may be hidden or clipped by
  2969.        an enclosing layer, in which case we should unmap the
  2970.        applet's window */
  2971.     XtSetMappedWhenManaged((Widget)window, visible);
  2972. }
  2973.  
  2974. #endif /* JAVA */
  2975.  
  2976. void
  2977. XFE_DisplayJavaApp(MWContext *context,
  2978.            int iLocation, LO_JavaAppStruct *java_struct)
  2979. {
  2980. #ifdef JAVA
  2981.     LJ_DisplayJavaApp(context, java_struct,
  2982.               FE_DisplayNoJavaIcon,
  2983.               FE_GetFullWindowSize,
  2984.               FE_CreateJavaWindow,
  2985.                       FE_GetAwtWindow,
  2986.               FE_RestoreJavaWindow,
  2987.               FE_SetJavaWindowPos,
  2988.               FE_SetJavaWindowVisibility);
  2989. #endif /* JAVA */
  2990. }
  2991.  
  2992. void
  2993. XFE_DrawJavaApp(MWContext *context,
  2994.            int iLocation, LO_JavaAppStruct *java_struct)
  2995. {
  2996. }
  2997.  
  2998. void
  2999. XFE_GetJavaAppSize (MWContext *context, LO_JavaAppStruct *java_struct,
  3000.             NET_ReloadMethod reloadMethod)
  3001. {
  3002. #ifdef JAVA
  3003.     LJ_GetJavaAppSize(context, java_struct, reloadMethod);
  3004. #else
  3005.     FE_DisplayNoJavaIcon(context, java_struct);
  3006.     java_struct->width = 1;
  3007.     java_struct->height = 1;
  3008. #endif
  3009. }
  3010.  
  3011. /*************************************************************************
  3012.  * End of Java Stuff
  3013.  ************************************************************************/
  3014.  
  3015.  
  3016. void 
  3017. XFE_HandleClippingView(MWContext *context, struct LJAppletData *appletD,
  3018.                int x, int y, int width, int height)
  3019. {
  3020. }
  3021.  
  3022. void
  3023. fe_ReLayout (MWContext *context, NET_ReloadMethod force_reload)
  3024. {
  3025.   LO_Element *e = LO_XYToNearestElement (context,
  3026.                      CONTEXT_DATA (context)->document_x,
  3027.                      CONTEXT_DATA (context)->document_y,
  3028.                                          NULL);
  3029.   History_entry *he = SHIST_GetCurrent (&context->hist);
  3030.   URL_Struct *url;
  3031.   /* We must store the position into the History_entry before making
  3032.      a URL_Struct from it. */
  3033.   if (e && he)
  3034.     SHIST_SetPositionOfCurrentDoc (&context->hist, e->lo_any.ele_id);
  3035.  
  3036.   if (he)
  3037.     url = (force_reload == NET_RESIZE_RELOAD)
  3038.     ? SHIST_CreateWysiwygURLStruct (context, he)
  3039.     : SHIST_CreateURLStructFromHistoryEntry (context, he);
  3040.   else if (sploosh)
  3041.     url = NET_CreateURLStruct (sploosh, FALSE);
  3042.   else
  3043.     url = 0;
  3044.  
  3045.   if (url)
  3046.     {
  3047.       if (force_reload != NET_DONT_RELOAD)
  3048.     url->force_reload = force_reload;
  3049.  
  3050.       /* warn plugins that the page relayout is not disasterous so that
  3051.      it can fake caching their instances */
  3052.       /* XXX Only need to do this if you're eventually going to call
  3053.          NPL_EmbedDelete(), which doesn't appear to be the case?
  3054.       if (force_reload == NET_RESIZE_RELOAD || force_reload == NET_DONT_RELOAD)
  3055.     NPL_SamePage (context);
  3056.       */
  3057.  
  3058.       fe_GetURL (context, url, FALSE);
  3059.     }
  3060. }
  3061.  
  3062.  
  3063. /* Following links */
  3064.  
  3065. /* Returns the URL string of the LO_Element, if it has one.
  3066.    Returns "" for LO_ATTR_ISFORM, which are a total kludge...
  3067.  */
  3068. static char *
  3069. fe_url_of_xref (MWContext *context, LO_Element *xref, long x, long y)
  3070. {
  3071.   switch (xref->type)
  3072.     {
  3073.     case LO_TEXT:
  3074.       if (xref->lo_text.anchor_href)
  3075.     {
  3076.       return (char *) xref->lo_text.anchor_href->anchor;
  3077.     }
  3078.       else
  3079.     {
  3080.           return (char *) NULL;
  3081.     }
  3082.  
  3083.     case LO_IMAGE:
  3084.       if (xref->lo_image.is_icon &&
  3085.           xref->lo_image.icon_number == IL_IMAGE_DELAYED)
  3086.         {
  3087.           long width, height;
  3088.  
  3089.           fe_IconSize(IL_IMAGE_DELAYED, &width, &height);
  3090.           if (xref->lo_image.alt &&
  3091.               xref->lo_image.alt_len &&
  3092.               (x > xref->lo_image.x + xref->lo_image.x_offset + 1 + 4 +
  3093.                   width))
  3094.             {
  3095.               if (xref->lo_image.anchor_href)
  3096.                 {
  3097.                   return (char *) xref->lo_image.anchor_href->anchor;
  3098.                 }
  3099.               else
  3100.                 {
  3101.                   return (char *) NULL;
  3102.                 }
  3103.             }
  3104.           else
  3105.             {
  3106.               return (char *) xref->lo_image.image_url;
  3107.             }
  3108.         }
  3109.       else if (xref->lo_image.image_attr->attrmask & LO_ATTR_ISFORM)
  3110.         {
  3111.           return "";
  3112.         }
  3113.       /*
  3114.        * This would be a client-side usemap image.
  3115.        */
  3116.       else if (xref->lo_image.image_attr->usemap_name != NULL)
  3117.         {
  3118.           LO_AnchorData *anchor_href;
  3119.  
  3120.           long ix = xref->lo_image.x + xref->lo_image.x_offset;
  3121.           long iy = xref->lo_image.y + xref->lo_image.y_offset;
  3122.           long mx = x - ix - xref->lo_image.border_width;
  3123.           long my = y - iy - xref->lo_image.border_width;
  3124.  
  3125.           anchor_href = LO_MapXYToAreaAnchor(context, (LO_ImageStruct *)xref,
  3126.                             mx, my);
  3127.           if (anchor_href)
  3128.             {
  3129.               if (anchor_href->alt)
  3130.                 {
  3131.                   return (char *) anchor_href->alt;
  3132.                 }
  3133.               else
  3134.                 {
  3135.                   return (char *) anchor_href->anchor;
  3136.                 }
  3137.             }
  3138.           else
  3139.             {
  3140.               return (char *) NULL;
  3141.             }
  3142.         }
  3143.       else
  3144.         {
  3145.           if (xref->lo_image.anchor_href)
  3146.             {
  3147.               return (char *) xref->lo_image.anchor_href->anchor;
  3148.             }
  3149.           else
  3150.             {
  3151.               return (char *) NULL;
  3152.             }
  3153.         }
  3154.  
  3155.     default:
  3156.       return 0;
  3157.     }
  3158. }
  3159.  
  3160. void
  3161. fe_EventLOCoords (MWContext *context, XEvent *event,
  3162.           unsigned long *x, unsigned long *y)
  3163. {
  3164.   *x = 0;
  3165.   *y = 0;
  3166.  
  3167.   switch (event->xany.type)
  3168.     {
  3169.     case ButtonPress:
  3170.     case ButtonRelease:
  3171.       *x = event->xbutton.x;
  3172.       *y = event->xbutton.y;
  3173.       break;
  3174.  
  3175.     case MotionNotify:
  3176.       *x = event->xmotion.x;
  3177.       *y = event->xmotion.y;
  3178.       break;
  3179.  
  3180.     case KeyPress:
  3181.     case KeyRelease:
  3182.       *x=event->xkey.x;
  3183.       *x=event->xkey.y;
  3184.       break;
  3185.  
  3186.     default:
  3187.       fprintf(stderr,
  3188.           "fe_EventLOCoords(): unknown XEvent type %d\n",
  3189.           event->xany.type);
  3190.       abort ();
  3191.       break;
  3192.     }
  3193.  
  3194.   *x += CONTEXT_DATA (context)->document_x;
  3195.   *y += CONTEXT_DATA (context)->document_y;
  3196. }
  3197.  
  3198. /* Returns the LO_Element under the mouse, if it is an anchor. */
  3199. static LO_Element *
  3200. fe_anchor_of_action (MWContext *context, CL_Event *layer_event,
  3201.                      CL_Layer *layer)
  3202. {
  3203.   LO_Element *le;
  3204.   unsigned long x, y;
  3205.   x = layer_event->x;
  3206.   y = layer_event->y;
  3207.   le = LO_XYToElement (context, x, y, layer);
  3208.   if (le && !fe_url_of_xref (context, le, x, y) && (le->type != LO_EDGE))
  3209.     le = 0;
  3210.   return le;
  3211. }
  3212.  
  3213. static void fe_WidgetLOCoords(MWContext *context, Widget widget,
  3214.                   unsigned long *x, unsigned long *y)
  3215. {
  3216.   Position wx, wy;
  3217.  
  3218.   XtVaGetValues(widget,XmNx,&wx,XmNy,&wy,NULL);
  3219.  
  3220.   (*x)=wx;
  3221.   (*y)=wy;
  3222.  
  3223.   *x += CONTEXT_DATA (context)->document_x;
  3224.   *y += CONTEXT_DATA (context)->document_y;
  3225. }
  3226.      
  3227.  
  3228. /* Returns the LO_Element of the widget, if it is a form element. */
  3229. static LO_Element *
  3230. fe_text_of_widget (MWContext *context, Widget widget,
  3231.                      CL_Layer *layer)
  3232. {
  3233.   LO_Element *le;
  3234.   unsigned long x, y;
  3235.  
  3236.   fe_WidgetLOCoords(context, widget, &x, &y);
  3237.  
  3238.   le = LO_XYToElement (context, x, y, layer);
  3239.   if (le && (le->type != LO_FORM_ELE))
  3240.     return NULL;
  3241.  
  3242.   return le;
  3243. }
  3244.  
  3245.  
  3246. void
  3247. fe_SetCursor (MWContext *context, Boolean over_link_p)
  3248. {
  3249.   Cursor c;
  3250.  
  3251.   if (CONTEXT_DATA (context)->save_next_mode_p)
  3252.     {
  3253.       if (over_link_p)
  3254.     c = CONTEXT_DATA (context)->save_next_link_cursor;
  3255.       else
  3256.     c = CONTEXT_DATA (context)->save_next_nonlink_cursor;
  3257.     }
  3258.   else if (CONTEXT_DATA (context)->clicking_blocked ||
  3259.        CONTEXT_DATA (context)->synchronous_url_dialog)
  3260.     {
  3261.       c = CONTEXT_DATA (context)->busy_cursor;
  3262.     }
  3263.   else
  3264.     {
  3265.       if (over_link_p)
  3266.     c = CONTEXT_DATA (context)->link_cursor;
  3267.       else
  3268.     c = None;
  3269.     }
  3270.   if (CONTEXT_DATA (context)->drawing_area) {
  3271.     XDefineCursor (XtDisplay (CONTEXT_DATA (context)->drawing_area),
  3272.            XtWindow (CONTEXT_DATA (context)->drawing_area),
  3273.            c);
  3274.   }
  3275. }
  3276.  
  3277. static int click_x = -1, click_y = -1;    /* gag */
  3278. static Boolean moving = False;
  3279. static XtIntervalId auto_scroll_timer = 0;
  3280. static int fe_auto_scroll_x = 0;
  3281. static int fe_auto_scroll_y = 0;
  3282.  
  3283. static void
  3284. fe_auto_scroll_timer (XtPointer closure, XtIntervalId *id)
  3285. {
  3286.   MWContext *context = closure;
  3287.   int scale = 50; /* #### */
  3288.   int msecs = 10; /* #### */
  3289.   long new_x = (CONTEXT_DATA (context)->document_x +
  3290.         (scale * fe_auto_scroll_x));
  3291.   long new_y = (CONTEXT_DATA (context)->document_y +
  3292.         (scale * fe_auto_scroll_y));
  3293.  
  3294.   LO_ExtendSelection (context, new_x, new_y);
  3295.   fe_ScrollTo (context, (new_x > 0 ? new_x : 0), (new_y > 0 ? new_y : 0));
  3296.  
  3297.   auto_scroll_timer =
  3298.     XtAppAddTimeOut (fe_XtAppContext, msecs, fe_auto_scroll_timer, closure);
  3299. }
  3300.  
  3301. /* Invoked via a translation on <Btn1Down> and <Btn2Down>.
  3302.  */
  3303. extern void fe_HTMLDragSetLayer(CL_Layer *layer);
  3304.  
  3305. static void
  3306. fe_arm_link_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
  3307. {
  3308.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  3309.   CL_Event layer_event;
  3310.   fe_EventStruct fe_event;
  3311.  
  3312.   /* Clear global HTMLView drag layer.
  3313.    * If event gets dispatched to a layer, then a new value will be set
  3314.    * by fe_arm_link_action_for_layer()
  3315.    */
  3316.   fe_HTMLDragSetLayer(NULL);
  3317.  
  3318.   XP_ASSERT (context);
  3319.   if (!context) return;
  3320.  
  3321.   fe_UserActivity (context);
  3322.  
  3323.   fe_NeutralizeFocus (context);
  3324.  
  3325.   if (CONTEXT_DATA (context)->clicking_blocked ||
  3326.       CONTEXT_DATA (context)->synchronous_url_dialog)
  3327.     {
  3328.       XBell (XtDisplay (widget), 0);
  3329.       return;
  3330.     }
  3331.  
  3332.   /* Fill in FE part of layer_event. */
  3333. #ifdef LAYERS_FULL_FE_EVENT
  3334.   fe_event.event = event;
  3335.   fe_event.av = av;
  3336.   fe_event.ac = ac;
  3337.   fe_event.mouse_action = FE_ARM_LINK;
  3338. #else
  3339.   fe_event_stuff(context,&fe_event,event,av,ac,FE_ARM_LINK);
  3340.   layer_event.fe_event_size = sizeof(fe_event);
  3341. #endif
  3342.  
  3343.   layer_event.fe_event = (void *)&fe_event;
  3344.  
  3345.  
  3346.   layer_event.type = CL_EVENT_MOUSE_BUTTON_DOWN;
  3347.   layer_event.which = event->xbutton.button;
  3348.   layer_event.modifiers = xfeToLayerModifiers(event->xbutton.state);
  3349.  
  3350.   if (context->compositor)
  3351.       {
  3352.           unsigned long x, y;
  3353.  
  3354.           fe_EventLOCoords (context, event, &x, &y);
  3355.           layer_event.x = x;
  3356.           layer_event.y = y;
  3357.  
  3358.           CL_DispatchEvent(context->compositor, &layer_event);
  3359.       }
  3360.   else
  3361.       {
  3362.           fe_arm_link_action_for_layer(context, NULL, &layer_event);
  3363.       }
  3364. }
  3365.  
  3366.  
  3367. /* Layer specific actions.  fe_arm_link_action() */
  3368. void
  3369. fe_arm_link_action_for_layer(MWContext *context, CL_Layer *layer,
  3370.                              CL_Event *layer_event)
  3371. {
  3372.   LO_Element *xref;
  3373.   unsigned long x, y;
  3374.   Time time;
  3375.  
  3376.   /* Note that the av and ac parameters that were passed to 
  3377.      fe_arm_link_action() can be obtained from the fe_event structure. */
  3378.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  3379. #ifdef LAYERS_FULL_FE_EVENT
  3380.   XEvent *event = fe_event->event;
  3381. #else
  3382.   XEvent *event = fe_event_extract(fe_event,NULL,NULL,NULL);
  3383. #endif
  3384.  
  3385.   if (context->compositor)
  3386.       CL_GrabMouseEvents(context->compositor, layer);
  3387.  
  3388.   xref = fe_anchor_of_action (context, layer_event, layer);
  3389.  
  3390.   time = (event && (event->type == KeyPress ||
  3391.             event->type == KeyRelease)
  3392.            ? event->xkey.time :
  3393.            event && (event->type == ButtonPress ||
  3394.              event->type == ButtonRelease)
  3395.            ? event->xbutton.time :
  3396.            XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  3397.  
  3398.   x = layer_event->x;
  3399.   y = layer_event->y;
  3400.   fe_DisownSelection (context, time, False);
  3401.   LO_StartSelection (context, x, y, layer);
  3402.  
  3403.   click_x = x;
  3404.   click_y = y;
  3405.   moving = False;
  3406.  
  3407. #ifdef DEBUG
  3408.   if (last_armed_xref)
  3409.     fprintf (stderr,
  3410.          "%s: ArmLink() invoked twice without intervening DisarmLink()?\n",
  3411.          fe_progname);
  3412. #endif
  3413.  
  3414.   last_armed_xref = xref;
  3415.   if (xref)
  3416.     {
  3417.       LO_HighlightAnchor (context, last_armed_xref, True);
  3418.       last_armed_xref_highlighted_p = True;
  3419.     }
  3420.   else
  3421.     {
  3422.       last_armed_xref_highlighted_p = False;
  3423.     }
  3424.  
  3425.   if (CONTEXT_DATA (context)->save_next_mode_p)
  3426.     {
  3427.       if (! xref)
  3428.     {
  3429.       XBell (XtDisplay (CONTEXT_WIDGET(context)), 0);
  3430.       CONTEXT_DATA (context)->save_next_mode_p = False;
  3431.       fe_SetCursor (context, False);
  3432.       XFE_Progress (context,
  3433.             fe_globalData.click_to_save_cancelled_message);
  3434.     }
  3435.     }
  3436. }
  3437.  
  3438. static void
  3439. fe_disarm_link_action_by_context(MWContext* context, XEvent *event,
  3440.                  String *av, Cardinal *ac);
  3441.  
  3442. /* Invoked via a translation on <Btn1Up>
  3443.  */
  3444. static void
  3445. fe_disarm_link_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
  3446. {
  3447.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  3448.   fe_disarm_link_action_by_context(context, event, av, ac);
  3449. }
  3450.  
  3451. static void
  3452. fe_disarm_link_action_by_context(MWContext* context, XEvent *event,
  3453.                  String *av, Cardinal *ac)
  3454. {
  3455. #ifndef LAYERS_SEPARATE_DISARM
  3456.   Time time;
  3457. #endif /* LAYERS_SEPARATE_DISARM */
  3458.  
  3459.   XP_ASSERT (context);
  3460.  
  3461.   if (!context) return;
  3462.  
  3463.   if (auto_scroll_timer)
  3464.     {
  3465.       XtRemoveTimeOut (auto_scroll_timer);
  3466.       auto_scroll_timer = 0;
  3467.     }
  3468.  
  3469.   fe_UserActivity (context);
  3470.  
  3471. #ifdef LAYERS_SEPARATE_DISARM
  3472.  
  3473.   /* Fill in FE part of layer_event. */
  3474. #ifdef LAYERS_FULL_FE_EVENT
  3475.   fe_event.event = event;
  3476.   fe_event.av = av;
  3477.   fe_event.ac = ac;
  3478.   fe_event.mouse_action = FE_DISARM_LINK;
  3479. #else
  3480.   fe_event_stuff(context,&fe_event,event,av,ac,FE_DISARM_LINK);
  3481.   layer_event.fe_event_size = sizeof(fe_event);
  3482. #endif
  3483.   layer_event.fe_event = (void *)&fe_event;
  3484.  
  3485.   layer_event.type = CL_EVENT_MOUSE_BUTTON_UP;
  3486.   layer_event.which = event->xbutton.button;
  3487.   layer_event.modifiers = xfeToLayerModifiers(event->xbutton.state);
  3488.  
  3489.   if (context->compositor)
  3490.       {
  3491.           unsigned long x, y;
  3492.  
  3493.           fe_EventLOCoords (context, event, &x, &y);
  3494.           layer_event.x = x;
  3495.           layer_event.y = y;
  3496.  
  3497.           CL_DispatchEvent(context->compositor, &layer_event);
  3498.       }
  3499.   else
  3500.       {
  3501.           fe_disarm_link_action_for_layer(context, NULL, &layer_event);
  3502.       }
  3503. }
  3504.  
  3505.  
  3506. /* Layer specific actions.  fe_disarm_link_action() */
  3507. void
  3508. fe_disarm_link_action_for_layer(MWContext *context, CL_Layer *layer,
  3509.                                 CL_Event *layer_event)
  3510. {
  3511.   Time time;
  3512.   /* Note that the av and ac parameters that were passed to 
  3513.      fe_disarm_link_action() can be obtained from the fe_event structure. */
  3514.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  3515. #ifdef LAYERS_FULL_FE_EVENT
  3516.   XEvent *event = fe_event->event;
  3517. #else
  3518.   XEvent *event = fe_event_extract(fe_event,NULL,NULL,NULL);
  3519. #endif
  3520.  
  3521.   if (context->compositor)
  3522.       CL_GrabMouseEvents(context->compositor, NULL);
  3523. #endif /* LAYERS_SEPARATE_DISARM */
  3524.  
  3525.   time = (event && (event->type == KeyPress ||
  3526.             event->type == KeyRelease)
  3527.            ? event->xkey.time :
  3528.            event && (event->type == ButtonPress ||
  3529.              event->type == ButtonRelease)
  3530.            ? event->xbutton.time :
  3531.            XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  3532.   LO_EndSelection (context);
  3533.   fe_OwnSelection (context, time, False);
  3534.  
  3535.   if (last_armed_xref)
  3536.     {
  3537.       LO_HighlightAnchor (context, last_armed_xref, False);
  3538.     }
  3539.  
  3540.   last_armed_xref = 0;
  3541.   last_armed_xref_highlighted_p = False;
  3542. }
  3543.  
  3544. /* Invoked via a translation on <Btn1Motion>
  3545.  */
  3546. static void
  3547. fe_disarm_link_if_moved_action (Widget widget, XEvent *event,
  3548.                 String *av, Cardinal *ac)
  3549. {
  3550.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  3551.   CL_Event layer_event;
  3552.   fe_EventStruct fe_event;
  3553.  
  3554.   XP_ASSERT (context);
  3555.   if (!context) return;
  3556.  
  3557.   /* Fill in FE part of layer_event. */
  3558. #ifdef LAYERS_FULL_FE_EVENT
  3559.   fe_event.event = event;
  3560.   fe_event.av = av;
  3561.   fe_event.ac = ac;
  3562.   fe_event.mouse_action = FE_DISARM_LINK_IF_MOVED;
  3563. #else
  3564.   fe_event_stuff(context,&fe_event,event,av,ac,FE_DISARM_LINK_IF_MOVED);
  3565.   layer_event.fe_event_size = sizeof(fe_event);
  3566. #endif
  3567.   layer_event.fe_event = (void *)&fe_event;
  3568.  
  3569.   layer_event.type = CL_EVENT_MOUSE_MOVE;
  3570.   layer_event.which = 0;
  3571.   layer_event.modifiers=0;
  3572.   
  3573.   if (context->compositor)
  3574.       {
  3575.           unsigned long x, y;
  3576.  
  3577.           fe_EventLOCoords (context, event, &x, &y);
  3578.           layer_event.x = x;
  3579.           layer_event.y = y;
  3580.           CL_DispatchEvent(context->compositor, &layer_event);
  3581.       }
  3582.   else
  3583.       {
  3584.           fe_disarm_link_if_moved_action_for_layer(context, NULL,
  3585.                                                    &layer_event);
  3586.       }
  3587. }
  3588.  
  3589.  
  3590. /* Layer specific actions.  fe_disarm_link_if_moved action() */
  3591. void
  3592. fe_disarm_link_if_moved_action_for_layer(MWContext *context, CL_Layer *layer,
  3593.                                          CL_Event *layer_event)
  3594. {
  3595.   LO_Element *xref;
  3596.   Boolean same_xref;
  3597.   unsigned long x, y;
  3598.   /* Note that the av and ac parameters that were passed to 
  3599.      fe_disarm_link_if_moved_action() can be obtained from the 
  3600.      fe_event structure. */
  3601.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  3602. #ifdef LAYERS_FULL_FE_EVENT
  3603.   XEvent *event = fe_event->event;
  3604. #else
  3605.   XEvent *event = fe_event_extract(fe_event,NULL,NULL,NULL);
  3606. #endif
  3607.  
  3608.   xref = fe_anchor_of_action (context, layer_event, layer);
  3609.  
  3610.   x = layer_event->x;
  3611.   y = layer_event->y;
  3612.  
  3613.   same_xref = (last_armed_xref && xref &&
  3614.            fe_url_of_xref (context, last_armed_xref, x, y) ==
  3615.            fe_url_of_xref (context, xref, x, y));
  3616.  
  3617.   if (!moving &&
  3618.       (x > click_x + CONTEXT_DATA (context)->hysteresis ||
  3619.        x < click_x - CONTEXT_DATA (context)->hysteresis ||
  3620.        y > click_y + CONTEXT_DATA (context)->hysteresis ||
  3621.        y < click_y - CONTEXT_DATA (context)->hysteresis))
  3622.     moving = True;
  3623.  
  3624.   if (moving &&
  3625.       !CONTEXT_DATA (context)->clicking_blocked &&
  3626.       !CONTEXT_DATA (context)->synchronous_url_dialog)
  3627.     {
  3628.       int x_region, y_region;
  3629.  
  3630.       if (event->xmotion.x < 0)
  3631.     x_region = -1;
  3632.       else if (event->xmotion.x > CONTEXT_DATA (context)->scrolled_width)
  3633.     x_region = 1;
  3634.       else
  3635.     x_region = 0;
  3636.  
  3637.       if (event->xmotion.y < 0)
  3638.     y_region = -1;
  3639.       else if (event->xmotion.y > CONTEXT_DATA (context)->scrolled_height)
  3640.     y_region = 1;
  3641.       else
  3642.     y_region = 0;
  3643.  
  3644.       if (last_armed_xref && last_armed_xref_highlighted_p)
  3645.     {
  3646.       LO_HighlightAnchor (context, last_armed_xref, False);
  3647.       last_armed_xref = 0;
  3648.       last_armed_xref_highlighted_p = False;
  3649.       fe_SetCursor (context, False);
  3650.     }
  3651.       LO_ExtendSelection (context, x, y);
  3652.  
  3653.       fe_auto_scroll_x = x_region;
  3654.       fe_auto_scroll_y = y_region;
  3655.  
  3656.       if ((x_region != 0 || y_region != 0) && !auto_scroll_timer)
  3657.     {
  3658.       /* turn on the timer */
  3659.       fe_auto_scroll_timer (context, 0);
  3660.     }
  3661.       else if ((x_region == 0 && y_region == 0) && auto_scroll_timer)
  3662.     {
  3663.       /* cancel the timer */
  3664.       XtRemoveTimeOut (auto_scroll_timer);
  3665.       auto_scroll_timer = 0;
  3666.     }
  3667.     }
  3668.  
  3669.   if (!last_armed_xref)
  3670.     return;
  3671.  
  3672.   if (!same_xref && last_armed_xref_highlighted_p)
  3673.     {
  3674.       LO_HighlightAnchor (context, last_armed_xref, False);
  3675.       last_armed_xref_highlighted_p = False;
  3676.     }
  3677.   else if (same_xref && !last_armed_xref_highlighted_p)
  3678.     {
  3679.       LO_HighlightAnchor (context, last_armed_xref, True);
  3680.       last_armed_xref_highlighted_p = True;
  3681.     }
  3682. }
  3683.  
  3684. typedef struct fe_mocha_closure {
  3685.   long x;
  3686.   long y;
  3687.   LO_FormSubmitData *data;
  3688.   LO_AnchorData *anchor_data;
  3689.   URL_Struct *url;
  3690.   XEvent *event;
  3691.   CL_Event *layer_event;
  3692.   Boolean save_p;
  3693.   Boolean other_p;
  3694.   Boolean image_delayed_p;
  3695.   Boolean free_element_p;
  3696.   String *av;
  3697.   Cardinal *ac;
  3698. } fe_mocha_closure;
  3699.  
  3700. static Boolean fe_FinishHREF (MWContext *context, 
  3701.                   LO_Element *element, 
  3702.                   fe_mocha_closure *closure);
  3703.  
  3704. static void fe_ParseHREF (MWContext *context,
  3705.               LO_Element *element,
  3706.               fe_mocha_closure *closure);
  3707.  
  3708. static void
  3709. fe_mocha_handle_submit (MWContext *context, LO_Element *element, int32 event,
  3710.             void *closure, ETEventStatus status)
  3711. {
  3712.   fe_mocha_closure *mocha_closure = (fe_mocha_closure *) closure;
  3713.   LO_FormSubmitData *data = NULL;
  3714.   char *action = NULL;
  3715.  
  3716.   if (status != EVENT_OK)  {
  3717.     XP_FREE (mocha_closure);
  3718.     return;
  3719.   }
  3720.  
  3721.   data = LO_SubmitImageForm (context, &element->lo_image,
  3722.                  mocha_closure->x, 
  3723.                  mocha_closure->y);
  3724.   if (data == NULL) {
  3725.     XP_FREE (mocha_closure);
  3726.     return;    /* XXX ignored anyway? what is right? */
  3727.   }
  3728.     
  3729.   action = (char *) data->action;
  3730.   mocha_closure->data = data;
  3731.   mocha_closure->url = NET_CreateURLStruct (action, FALSE);
  3732.   NET_AddLOSubmitDataToURLStruct (data, mocha_closure->url);
  3733.   fe_FinishHREF (context, element, mocha_closure);
  3734.  
  3735.   if (mocha_closure->event) XP_FREE (mocha_closure->event);
  3736.   XP_FREE (mocha_closure);
  3737. }
  3738.  
  3739. void fe_disarm_last_xref(void)
  3740. {
  3741.   XEvent* xevent;
  3742.  
  3743. #ifdef LAYERS_FULL_FE_EVENT
  3744.   xevent=&(last_armed_xref_closure_for_disarm.xevent);
  3745. #else
  3746.   xevent=fe_event_extract(&(last_armed_xref_closure_for_disarm.fe_event),
  3747.               NULL,NULL,NULL);
  3748. #endif
  3749.  
  3750.   fe_disarm_link_action_by_context(last_armed_xref_closure_for_disarm.context,
  3751.                 xevent,
  3752.                 NULL,NULL);
  3753. }
  3754.  
  3755. static void
  3756. fe_mocha_handle_click (MWContext *context, LO_Element *element, int32 event,
  3757.                void *closure, ETEventStatus status)
  3758. {
  3759.   fe_mocha_closure *mocha_closure = (fe_mocha_closure *) closure;
  3760.  
  3761.   if (status != EVENT_OK)
  3762.     {
  3763.       if (status==EVENT_PANIC)
  3764.     {
  3765.       last_armed_xref = 0;
  3766.       last_armed_xref_highlighted_p = False;
  3767.     }
  3768.       else
  3769.     fe_disarm_last_xref();
  3770.       if (mocha_closure)
  3771.     XP_FREE (mocha_closure);
  3772.       return;
  3773.     }
  3774.  
  3775.   fe_disarm_last_xref();
  3776.  
  3777.   /* mocha may have swapped our url - call the parsing code now. */
  3778.   fe_ParseHREF (context, element, mocha_closure);
  3779.   fe_FinishHREF (context, element, mocha_closure);
  3780.  
  3781.   if (mocha_closure->free_element_p) XP_DELETE (element);
  3782.   if (mocha_closure->event) XP_FREE (mocha_closure->event);
  3783.   XP_FREE (mocha_closure);
  3784. }
  3785.  
  3786.  
  3787. /* Ok. Now we have to delay the parsing of the anchor info until
  3788.  * after mocha has had a chance to change anything it wants.
  3789.  */
  3790.  
  3791. static void fe_ParseHREF (MWContext *context,
  3792.               LO_Element *xref,
  3793.               fe_mocha_closure *mocha_closure)
  3794. {
  3795.   if (xref->type == LO_IMAGE)
  3796.     {
  3797.       if (xref->lo_image.is_icon &&
  3798.       xref->lo_image.icon_number == IL_IMAGE_DELAYED)
  3799.     {
  3800.       long width, height;
  3801.  
  3802.       fe_IconSize(IL_IMAGE_DELAYED, &width, &height);
  3803.       if (xref->lo_image.alt &&
  3804.           xref->lo_image.alt_len &&
  3805.           (mocha_closure->layer_event->x > xref->lo_image.x +
  3806.            xref->lo_image.x_offset + 1 + 4 + width))
  3807.         {
  3808.           char *anchor = NULL;
  3809.       
  3810.           if (xref->lo_image.anchor_href)
  3811.             {
  3812.               anchor = (char *) xref->lo_image.anchor_href->anchor;
  3813.               mocha_closure->anchor_data = xref->lo_image.anchor_href;
  3814.             }
  3815.           mocha_closure->url = NET_CreateURLStruct (anchor, FALSE);
  3816.         }
  3817.           else
  3818.         {
  3819.           mocha_closure->image_delayed_p = True;
  3820.           mocha_closure->url = NET_CreateURLStruct (
  3821.                       (char *) xref->lo_image.image_url,
  3822.                       FALSE);
  3823.         }
  3824.     }
  3825.       else if (xref->lo_image.image_attr->usemap_name != NULL)
  3826.     /* If this is a usemap image, map the x,y to a url */
  3827.     {
  3828.       char *anchor = NULL;
  3829.       LO_AnchorData *anchor_href;
  3830.       
  3831.       anchor_href = LO_MapXYToAreaAnchor(context,
  3832.                          (LO_ImageStruct *)xref, 
  3833.                          mocha_closure->x, 
  3834.                          mocha_closure->y);
  3835.       if (anchor_href)
  3836.         {
  3837.           mocha_closure->anchor_data = anchor_href;
  3838.           anchor = (char *) anchor_href->anchor;
  3839.         }
  3840.  
  3841.       /* The user clicked; tell libmocha */
  3842.       mocha_closure->url = NET_CreateURLStruct (anchor, FALSE);
  3843.     }
  3844.       else if (xref->lo_image.image_attr->attrmask & LO_ATTR_ISMAP)
  3845.     /* If this is an image map, append ?x?y to the URL. */
  3846.     {
  3847.       char *anchor = NULL;
  3848.       int x = mocha_closure->x;
  3849.       int y = mocha_closure->y;
  3850.       
  3851.       if (xref->lo_image.anchor_href)
  3852.         {
  3853.           anchor = (char *) xref->lo_image.anchor_href->anchor;
  3854.           mocha_closure->anchor_data = xref->lo_image.anchor_href;
  3855.         }
  3856.       mocha_closure->url = NET_CreateURLStruct (anchor, FALSE);
  3857.       NET_AddCoordinatesToURLStruct (mocha_closure->url, 
  3858.                      ((x < 0) ? 0 : x),
  3859.                      ((y < 0) ? 0 : y));
  3860.     }
  3861.       else
  3862.     {
  3863.       char *anchor = NULL;
  3864.       
  3865.       if (xref->lo_image.anchor_href)
  3866.         {
  3867.           anchor = (char *) xref->lo_image.anchor_href->anchor;
  3868.           mocha_closure->anchor_data = xref->lo_image.anchor_href;
  3869.         }
  3870.       mocha_closure->url = NET_CreateURLStruct (anchor, FALSE);
  3871.     }
  3872.     }
  3873.   else if (xref->type == LO_TEXT)
  3874.     {
  3875.       char *anchor = NULL;
  3876.       
  3877.       if (xref->lo_text.anchor_href)
  3878.     {
  3879.       anchor = (char *) xref->lo_text.anchor_href->anchor;
  3880.       mocha_closure->anchor_data = xref->lo_text.anchor_href;
  3881.     }
  3882.       mocha_closure->url = NET_CreateURLStruct (anchor, FALSE);
  3883.     }
  3884.   else if (xref->type == LO_EDGE)
  3885.     {
  3886.       /* Nothing to do here - should we ever get here? ### */
  3887.       ;
  3888.     }
  3889.   else
  3890.     {
  3891.       XP_ASSERT (False);
  3892.     }
  3893. }
  3894.  
  3895.  
  3896. Boolean fe_HandleHREF (MWContext *context,
  3897.                LO_Element *xref,
  3898.                        Boolean save_p,
  3899.                Boolean other_p,
  3900.                CL_Event *layer_event,
  3901.                CL_Layer *layer) /* in: may be NULL */
  3902. {
  3903.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  3904. #ifdef LAYERS_FULL_FE_EVENT
  3905.   XEvent *event = fe_event->event;
  3906.   String *av = fe_event->av;
  3907.   Cardinal *ac = fe_event->ac;
  3908. #else
  3909.   String *av;
  3910.   Cardinal *ac;
  3911.   XEvent *event = fe_event_extract(fe_event,&av,&ac,NULL);
  3912. #endif
  3913.   /*MWContext *top = NULL;*/
  3914.   /*LO_AnchorData *anchor_data = NULL;*/
  3915.   /*LO_FormSubmitData *data = NULL;*/
  3916.   fe_mocha_closure *mocha_closure = XP_NEW_ZAP(fe_mocha_closure);
  3917.  
  3918.   /* setup the mocha callback data */
  3919.   mocha_closure->save_p = save_p;
  3920.   mocha_closure->other_p = other_p;
  3921.   mocha_closure->event = XP_NEW_ZAP (XEvent);
  3922.   XP_MEMCPY (mocha_closure->event, event, sizeof (XEvent));
  3923.   mocha_closure->layer_event = XP_NEW_ZAP (CL_Event);
  3924.   XP_MEMCPY (mocha_closure->layer_event, layer_event, sizeof (CL_Event));
  3925.   /* mocha_closure->av = av; */
  3926.   /* mocha_closure->ac = ac; */
  3927.  
  3928.   if (xref->type == LO_IMAGE)
  3929.     {
  3930.       long cx = layer_event->x;
  3931.       long cy = layer_event->y;
  3932.       long ix = xref->lo_image.x + xref->lo_image.x_offset;
  3933.       long iy = xref->lo_image.y + xref->lo_image.y_offset;
  3934.       long x = cx - ix - xref->lo_image.border_width;
  3935.       long y = cy - iy - xref->lo_image.border_width;
  3936.  
  3937.       /* store these away */
  3938.       mocha_closure->x = x;
  3939.       mocha_closure->y = y;
  3940.  
  3941.       if (xref->lo_image.image_attr->attrmask & LO_ATTR_ISFORM)
  3942.     /* If this is a form image, submit it... */
  3943.     {
  3944.       {
  3945.         JSEvent *event = XP_NEW_ZAP(JSEvent);
  3946.         
  3947.         event->type = EVENT_SUBMIT;
  3948.         
  3949.         ET_SendEvent (context, (LO_Element *) &xref->lo_image, 
  3950.               event, fe_mocha_handle_submit,
  3951.               mocha_closure);
  3952.         return True;
  3953.       }
  3954.     }
  3955.       else if (xref->lo_image.image_attr->usemap_name != NULL)
  3956.     {
  3957.       LO_AnchorData *anchor_data;
  3958.  
  3959.       anchor_data = LO_MapXYToAreaAnchor(context, (LO_ImageStruct *)xref, x, y);
  3960.       if (anchor_data)
  3961.         {
  3962.           /* Imagemap area pretend to be links for JavaScript. */
  3963.           mocha_closure->free_element_p = True;
  3964.           xref = (LO_Element *) XP_NEW_ZAP(LO_Element);
  3965.           xref->lo_text.type = LO_TEXT;
  3966.           xref->lo_text.anchor_href = anchor_data;
  3967.  
  3968.           /* We use the text of the element to determine if it is still
  3969.              valid later so give the dummy text struct's text a value. */
  3970.           if (anchor_data->anchor)
  3971.         xref->lo_text.text = anchor_data->anchor;
  3972.         }
  3973.     }
  3974.     }
  3975.   {
  3976.     JSEvent *jsevent = XP_NEW_ZAP(JSEvent);
  3977.  
  3978.     jsevent->type = EVENT_CLICK;
  3979.  
  3980.     jsevent->x = layer_event->x;
  3981.     jsevent->y = layer_event->y;
  3982.     if (layer) {
  3983.       jsevent->docx = layer_event->x + CL_GetLayerXOrigin(layer);
  3984.       jsevent->docy = layer_event->y + CL_GetLayerYOrigin(layer);
  3985.     }
  3986.     else {
  3987.       jsevent->docx = layer_event->x;
  3988.       jsevent->docy = layer_event->y;
  3989.     }
  3990.     jsevent->which = layer_event->which;
  3991.     jsevent->modifiers = layer_event->modifiers;
  3992.     jsevent->screenx = event->xbutton.x_root;
  3993.     jsevent->screeny = event->xbutton.y_root;
  3994.     ET_SendEvent (context, (LO_Element *) xref,
  3995.           jsevent, fe_mocha_handle_click,
  3996.           mocha_closure);
  3997.     return True;
  3998.   }
  3999.  
  4000.   return False;
  4001. }
  4002.  
  4003. static Boolean
  4004. fe_FinishHREF (MWContext *context, 
  4005.            LO_Element *element, 
  4006.            fe_mocha_closure *mocha_closure)
  4007. {
  4008.   MWContext *top = NULL;
  4009.   URL_Struct *url        = mocha_closure->url;
  4010.   LO_FormSubmitData *data    = mocha_closure->data;
  4011.   LO_AnchorData *anchor_data    = mocha_closure->anchor_data;
  4012.   XEvent *event            = mocha_closure->event;
  4013.   Boolean image_delayed_p    = mocha_closure->image_delayed_p;
  4014.   Boolean other_p        = mocha_closure->other_p;
  4015.   Boolean save_p        = mocha_closure->save_p;
  4016.   String *av            = mocha_closure->av;
  4017.   Cardinal *ac            = mocha_closure->ac;
  4018.   Boolean link_selected_p = False;
  4019.  
  4020.     {
  4021.  
  4022.         /* Add the referer to the URL. */
  4023.         History_entry *he = SHIST_GetCurrent (&context->hist);
  4024.         if (url->referer) {
  4025.             free (url->referer);
  4026.             url->referer = 0;
  4027.         }
  4028.         
  4029.         url->referer = fe_GetURLForReferral(he);
  4030.  
  4031. #ifdef MOZ_MAIL_NEWS
  4032.       if (MSG_NewWindowProhibited (context, url->address))
  4033.     {
  4034.       XP_ASSERT (!MSG_NewWindowRequired (context, url->address));
  4035.       other_p = False;
  4036.     }
  4037.       else if (MSG_NewWindowRequired (context, url->address))
  4038.     {
  4039.       MWContext *new_context = 0;
  4040.       XP_ASSERT (!MSG_NewWindowProhibited (context, url->address));
  4041.  
  4042.       /* If the user has clicked left (the "open in this window" gesture)
  4043.          on a link in a window which is not able to display that kind of
  4044.          URL (like, clicking on an HTTP link in a mail message) then we
  4045.          find an existing context of an appropriate type (in this case,
  4046.          a browser window) to display it in.  If there is no window of
  4047.          the appropriate type, of if they had used the `new window'
  4048.          gesture, then we create a new context of the apropriate type.
  4049.        */
  4050.       if (other_p)
  4051.         new_context = 0;
  4052.       else if (MSG_RequiresMailWindow (url->address))
  4053.         new_context = XP_FindContextOfType (context, MWContextMail);
  4054.       else if (MSG_RequiresNewsWindow (url->address))
  4055.         new_context = XP_FindContextOfType (context, MWContextNews);
  4056.       else if (MSG_RequiresBrowserWindow (url->address))
  4057.         {
  4058.           /* Be sure to skip nethelps when looking for context */
  4059.           new_context = fe_FindNonCustomBrowserContext(context);
  4060.         }
  4061.  
  4062.       if (!new_context)
  4063.         other_p = True;
  4064.       else
  4065.         {
  4066.           if (context != new_context)
  4067.         /* If we have picked an existing context that isn't this
  4068.            one in which to display this document, make sure that
  4069.            context is uniconified and raised first. */
  4070.         XMapRaised(XtDisplay(CONTEXT_WIDGET(new_context)),
  4071.                XtWindow(CONTEXT_WIDGET(new_context)));
  4072.           context = new_context;
  4073.         }
  4074.     }
  4075. #endif  /* MOZ_MAIL_NEWS */
  4076.  
  4077.       /* Regardless of how we got here, we need to make sure and
  4078.        * and use the toplevel context if our current one is a grid
  4079.        * cell. Grid cell's don't have chrome, and our new window
  4080.        * should.
  4081.        */
  4082.       top = XP_GetNonGridContext(context);
  4083.  
  4084.       if (save_p)
  4085.     {
  4086.       fe_SaveURL (context, url);
  4087.     }
  4088.       /*
  4089.        * definitely get here from middle-click, are there other ways?
  4090.        */
  4091.       else if (other_p)
  4092.     {
  4093.       /* Need to clear it right away, or it doesn't get cleared because
  4094.          we blast last_armed_xref from fe_ClearArea...  Sigh. */
  4095.       fe_disarm_link_action (CONTEXT_DATA (context)->drawing_area, event, av, ac);
  4096.  
  4097.       /*
  4098.        * When we middle-click for a new window we need
  4099.        * to ignore all window targets.  It is easy to ignore
  4100.        * the target on the anchor here, but we also need to
  4101.        * ignore other targets that might be set later.  We do
  4102.        * this by setting window_target in the URL struct, but
  4103.        * not setting a window name in the context.
  4104.        */
  4105.       url->window_target = strdup ("");
  4106.  
  4107.       /*
  4108.        * We no longer want to follow anchor targets from middle-clicks.
  4109.        */
  4110.       fe_MakeWindow (XtParent (CONTEXT_WIDGET (top)), top,
  4111.                  url, NULL, MWContextBrowser, FALSE);
  4112.     }
  4113.       else if (image_delayed_p)
  4114.         {
  4115.           fe_LoadDelayedImage (context, url->address);
  4116.           NET_FreeURLStruct (url);
  4117.         }
  4118.       /*
  4119.        * Else a normal click on a link.
  4120.        * Follow that link in this window.
  4121.        */
  4122.       else
  4123.     {
  4124.       /*
  4125.        * If this link was targetted to a name window we need to either
  4126.        * open it in that window (if it exists) or create a new window
  4127.        * to open this link in (and assign the name to).
  4128.        *
  4129.        * Ignore targets for ComposeWindow urls.
  4130.        */
  4131.       if ( ((anchor_data)&&(anchor_data->target))
  4132. #ifdef MOZ_MAIL_NEWS
  4133.         && !MSG_RequiresComposeWindow(url->address)
  4134. #endif
  4135.       )
  4136.         {
  4137.         MWContext *target_context = XP_FindNamedContextInList(context,
  4138.                         (char *)anchor_data->target);
  4139.         /*
  4140.          * If we copy the real target it, it will get processed
  4141.          * again at parse time.  This is bad, because magic names
  4142.          * like _parent return different values each time.
  4143.          * So if we put the magic empty string here, it prevents
  4144.          * us being overridden later, while not causing reprocessing.
  4145.          */
  4146.         url->window_target = strdup ("");
  4147.         /*
  4148.          * We found the named window, open this link there.
  4149.          */
  4150.         if (target_context)
  4151.           {
  4152.             fe_GetURL (target_context, url, FALSE);
  4153.           }
  4154.         /*
  4155.          * No such named window, create one and open the link there.
  4156.          */
  4157.         else
  4158.           {
  4159.             fe_MakeWindow (XtParent (CONTEXT_WIDGET (top)), top,
  4160.                    url, (char *)anchor_data->target,
  4161.                    MWContextBrowser, FALSE);
  4162.           }
  4163.         }
  4164.       /*
  4165.        * Else no target, just follow the link in this window.
  4166.        */
  4167.       else
  4168.         {
  4169.           fe_GetURL (context, url, FALSE);
  4170.         }
  4171.     }
  4172.  
  4173.       if (data)
  4174.     LO_FreeSubmitData (data);
  4175.  
  4176.       link_selected_p = True;
  4177.     }
  4178.     return link_selected_p;
  4179. }
  4180.  
  4181. /* Invoked via a translation on <Btn1Up>
  4182.  */
  4183. static void
  4184. fe_activate_link_action (Widget widget, XEvent *event,
  4185.              String *av, Cardinal *ac)
  4186. {
  4187.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  4188.   CL_Event layer_event;
  4189.   fe_EventStruct fe_event;
  4190.  
  4191.   XP_ASSERT (context);
  4192.   if (!context) return;
  4193.  
  4194.   fe_NeutralizeFocus (context);
  4195.  
  4196.   if (auto_scroll_timer)
  4197.     {
  4198.       XtRemoveTimeOut (auto_scroll_timer);
  4199.       auto_scroll_timer = 0;
  4200.     }
  4201.  
  4202.   fe_UserActivity (context);
  4203.  
  4204.   /* Fill in FE part of layer_event. */
  4205. #ifdef LAYERS_FULL_FE_EVENT
  4206.   fe_event.event = event;
  4207.   fe_event.av = av;
  4208.   fe_event.ac = ac;
  4209.   fe_event.mouse_action = FE_ACTIVATE_LINK;
  4210. #else
  4211.   fe_event_stuff(context,&fe_event,event,av,ac,FE_ACTIVATE_LINK);
  4212.   layer_event.fe_event_size = sizeof(fe_event);
  4213. #endif
  4214.   layer_event.fe_event = (void *)&fe_event;
  4215.  
  4216.   layer_event.type = CL_EVENT_MOUSE_BUTTON_UP;
  4217.   layer_event.which = event->xbutton.button;
  4218.   layer_event.modifiers = xfeToLayerModifiers(event->xbutton.state);
  4219.  
  4220.   if (context->compositor)
  4221.       {
  4222.           unsigned long x, y;
  4223.  
  4224.           fe_EventLOCoords (context, event, &x, &y);
  4225.           layer_event.x = x;
  4226.           layer_event.y = y;
  4227.  
  4228.           CL_DispatchEvent(context->compositor, &layer_event);
  4229.       }
  4230.   else
  4231.       {
  4232.           fe_activate_link_action_for_layer(context, NULL, &layer_event);
  4233.       }
  4234. }
  4235.  
  4236.  
  4237. /* Layer specific actions.  fe_activate_link_action() */
  4238. void
  4239. fe_activate_link_action_for_layer(MWContext *context, CL_Layer *layer,
  4240.                                   CL_Event *layer_event)
  4241. {
  4242.   LO_Element *xref;
  4243.   Boolean other_p = False;
  4244.   Boolean save_p = False;
  4245.   Boolean link_selected_p = False;
  4246.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  4247. #ifdef LAYERS_FULL_FE_EVENT
  4248.   String *av = fe_event->av;
  4249.   Cardinal *ac = fe_event->ac;
  4250. #else
  4251.   String *av;
  4252.   Cardinal *ac;
  4253.   XEvent* event=fe_event_extract(fe_event,&av,&ac,NULL);
  4254. #endif
  4255.  
  4256.   if (context->compositor)
  4257.       CL_GrabMouseEvents(context->compositor, NULL);
  4258.  
  4259.   xref = fe_anchor_of_action (context, layer_event, layer);
  4260.  
  4261.   if (*ac > 2)
  4262.     fprintf (stderr,
  4263.              XP_GetString(XFE_LAY_TOO_MANY_ARGS_TO_ACTIVATE_LINK_ACTION),
  4264.              fe_progname,*ac);
  4265.   else if (*ac == 1 && !strcmp ("new-window", av[0]))
  4266.     other_p = True;
  4267.   else if (*ac == 1 && !strcmp ("save-only", av[0]))
  4268.     save_p = True;
  4269.   else if (*ac > 0)
  4270.     fprintf (stderr,
  4271.              XP_GetString(XFE_LAY_UNKNOWN_PARAMETER_TO_ACTIVATE_LINK_ACTION),
  4272.          fe_progname, av[0]);
  4273.  
  4274.   if (CONTEXT_DATA (context)->save_next_mode_p)
  4275.     {
  4276.       save_p = True;
  4277.       CONTEXT_DATA (context)->save_next_mode_p = False;
  4278.     }
  4279.  
  4280.   /* Turn off the selection cursor.  It'll be updated again at next motion. */
  4281.   fe_SetCursor (context, False);
  4282.  
  4283.   if (   /* If a selection was made, don't follow the link. */
  4284.          (LO_HaveSelection (context))
  4285.       || CONTEXT_DATA (context)->clicking_blocked
  4286.       || CONTEXT_DATA (context)->synchronous_url_dialog
  4287.       || (!xref)
  4288.       || ((last_armed_xref) && (xref != last_armed_xref))
  4289.       )
  4290.     {
  4291.       fe_disarm_link_action_by_context(context,event,NULL,NULL);
  4292.  
  4293.       /*  If (1) there was no link and
  4294.        *     (2) there was no selection and
  4295.        *     (3) mouse button 2 was pressed and
  4296.        *     (4) mouse button was released and
  4297.        *     (5) this is a browser context
  4298.        *
  4299.        *  The user clicked button 2 on nothing.
  4300.        *
  4301.        *  Try to do the primary selection magic.
  4302.        */
  4303.            
  4304.       if (!xref && 
  4305.           !LO_HaveSelection (context) &&
  4306.           layer_event &&
  4307.           (layer_event->which == 2) &&
  4308.           (layer_event->type == CL_EVENT_MOUSE_BUTTON_UP) &&
  4309.           (context->type == MWContextBrowser) &&
  4310.           CONTEXT_WIDGET(context))
  4311.       {
  4312.           fe_PrimarySelectionFetchURL(context);
  4313.       }
  4314.     }
  4315.   else
  4316.     {
  4317. #ifdef LAYERS_FULL_FE_EVENT
  4318.       memcpy(&(last_armed_xref_closure_for_disarm.xevent),
  4319.          event,
  4320.          sizeof(XEvent));
  4321. #else
  4322.       last_armed_xref_closure_for_disarm.fe_event=(*fe_event);
  4323. #endif
  4324.       last_armed_xref_closure_for_disarm.context=context;
  4325.  
  4326.       link_selected_p = fe_HandleHREF (context, xref, save_p, other_p,
  4327.                        layer_event, layer);
  4328.     }
  4329.  
  4330. /* DONT ACCESS context AFTER A GetURL. fe_HandleHREF could do fe_GetURL. */
  4331.  
  4332. }
  4333.  
  4334. /* Invoked via a translation on <Motion>
  4335.  */
  4336. void
  4337. fe_describe_link_action (Widget widget, XEvent *event,
  4338.              String *av, Cardinal *ac)
  4339. {
  4340.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  4341.   CL_Event layer_event;
  4342.   fe_EventStruct fe_event;
  4343.  
  4344. /*   XP_ASSERT (context); */
  4345.   if (!context) return;
  4346.  
  4347.   /* Fill in FE part of layer_event. */
  4348. #ifdef LAYERS_FULL_FE_EVENT
  4349.   fe_event.event = event;
  4350.   fe_event.av = av;
  4351.   fe_event.ac = ac;
  4352.   fe_event.mouse_action = FE_DESCRIBE_LINK;
  4353. #else
  4354.   fe_event_stuff(context,&fe_event,event,av,ac,FE_DESCRIBE_LINK);
  4355.   layer_event.fe_event_size = sizeof(fe_event);
  4356. #endif
  4357.   layer_event.fe_event = (void *)&fe_event;
  4358.  
  4359.   layer_event.type = CL_EVENT_MOUSE_MOVE;
  4360.   layer_event.which = 0;
  4361.   layer_event.modifiers=0;
  4362.  
  4363.   if (context->compositor)
  4364.       {
  4365.           unsigned long x, y;
  4366.  
  4367.           fe_EventLOCoords (context, event, &x, &y);
  4368.           layer_event.x = x;
  4369.           layer_event.y = y;
  4370.           CL_DispatchEvent(context->compositor, &layer_event);
  4371.       }
  4372.   else
  4373.       {
  4374.           fe_describe_link_action_for_layer(context, NULL, &layer_event);
  4375.       }
  4376. }
  4377.  
  4378. static void
  4379. fe_mouse_over_callback(MWContext * context, LO_Element * lo_element, int32 event,
  4380.               void * pObj, ETEventStatus status)
  4381. {
  4382.  
  4383.     switch(status) {
  4384.     case EVENT_OK:
  4385. #ifdef DEBUG_spence
  4386.         printf ("fe_mouse_over_cb: event ok\n");
  4387. #endif
  4388.         break;
  4389.     case EVENT_PANIC:
  4390.         /* backend says don't do anything */
  4391. #ifdef DEBUG_spence
  4392.         printf ("fe_mouse_over_cb: event panic!\n");
  4393. #endif
  4394.         break;
  4395.     default:
  4396.       {
  4397. /*          char *url = NULL; */
  4398. #ifdef DEBUG_spence
  4399.         printf ("fe_mouse_over_cb: event !ok; we'll set the status bar\n");
  4400. #endif
  4401. #if 0
  4402.         /* backend didn't set the status bar, so we'll do it */
  4403.         if (event == EVENT_MOUSEOVER) {
  4404.             if (lo_element) {
  4405.                 url = (char *) lo_element->lo_text.anchor_href->alt;
  4406.                 if (url == NULL)
  4407.                     url = (char *) lo_element->lo_text.anchor_href->anchor;
  4408.             }
  4409.             if (url)
  4410.                 fe_MidTruncatedProgress (context, url);
  4411.         }
  4412. #endif /* 0 */
  4413.         break;
  4414.       }
  4415.     } /* end switch */
  4416.  
  4417.     /* Free the temporary dummy layout element. */
  4418.     XP_FREE(lo_element);
  4419. }
  4420.  
  4421. /* Layer specific actions.  fe_describe_link_action() */
  4422. void
  4423. fe_describe_link_action_for_layer(MWContext *context, CL_Layer *layer,
  4424.                                   CL_Event *layer_event)
  4425. {
  4426.   static XP_Bool m_isImage = False;
  4427.   MWContext *top = XP_GetNonGridContext (context);
  4428.   LO_Element *xref;
  4429.   LO_AnchorData *anchor_data = NULL;
  4430.   unsigned long x, y;
  4431.   long ix, iy, mx, my;
  4432.  
  4433.   /* Note that the av and ac parameters that were passed to 
  4434.      fe_describe_link_action() can be obtained from the fe_event structure. */
  4435.  
  4436.   xref = fe_anchor_of_action (context, layer_event, layer);
  4437.  
  4438.   x = layer_event->x;
  4439.   y = layer_event->y;
  4440.  
  4441.   {
  4442.       static LO_Element *m_lastLE = NULL;
  4443.  
  4444.       LO_Element *le = LO_XYToElement (context, x, y, layer);
  4445.  
  4446.       if (le && le->type == LO_IMAGE) {
  4447.           /* In image 
  4448.            */
  4449.           if (!m_isImage) {
  4450.               /* Enter image
  4451.                */
  4452.               fe_HTMLViewTooltipsEH(context, layer,    layer_event, 1);
  4453.           }/* if */
  4454.  
  4455.  
  4456.           m_isImage = True;
  4457.       }/* if */
  4458.       else {
  4459.           if (m_isImage) {
  4460.               /* Leave image
  4461.                */
  4462.               fe_HTMLViewTooltipsEH(context, layer,    layer_event, 4);
  4463.           }/* */
  4464.           m_isImage = False;
  4465.       }/* else */
  4466.       m_lastLE = le;
  4467.       /*
  4468.       XDBG(printf("\n fe_describe_link_action_for_layer, le->type=%d %s\n", 
  4469.                   le?le->type:-10,
  4470.                   (le && le->type==LO_IMAGE)?"-->>LO_IMAGE":""));
  4471.                   */
  4472.   }
  4473.   if (xref == NULL || xref != last_documented_xref  ||
  4474.       (last_documented_xref && (last_documented_xref->type == LO_IMAGE)&&
  4475.        (last_documented_xref->lo_image.image_attr->usemap_name != NULL)))
  4476.     {
  4477.       char *url = (xref ? fe_url_of_xref (context, xref, x, y) : 0);
  4478.       anchor_data = NULL;
  4479.       if (xref) {
  4480.           if (last_documented_xref != xref && xref->type == LO_TEXT)
  4481.               anchor_data = xref->lo_text.anchor_href;
  4482.           else if (xref->type == LO_IMAGE)
  4483.               if (xref->lo_image.image_attr->usemap_name != NULL) {
  4484.                   /* Image map */
  4485.                   ix = xref->lo_image.x + xref->lo_image.x_offset;
  4486.                   iy = xref->lo_image.y + xref->lo_image.y_offset;
  4487.                   mx = x - ix - xref->lo_image.border_width;
  4488.                   my = y - iy - xref->lo_image.border_width;
  4489.                   anchor_data =
  4490.                       LO_MapXYToAreaAnchor(context, (LO_ImageStruct *)xref, mx, my);
  4491.               }
  4492.               else if (last_documented_xref != xref)
  4493.                   anchor_data = xref->lo_image.anchor_href;
  4494.       }
  4495.       
  4496.       /* send mouse out mocha event only if we have left a link.
  4497.        * conditions are :
  4498.        *  i) left a link to go to a non-link
  4499.        * ii) left a link to go to another link
  4500.        * iii) Moving around inside an image
  4501.        * Note: Mouse Out must happen before mouse over.
  4502.        */
  4503.       if (last_documented_anchor_data && last_documented_xref
  4504.           && last_documented_xref_context)
  4505.           if (last_documented_anchor_data != anchor_data) {
  4506.               JSEvent *event;
  4507.               LO_Element *dummy_xref = (LO_Element *) XP_NEW_ZAP (LO_Element);
  4508.  
  4509.               TRACEMSG (("sending MouseOut\n"));
  4510.  
  4511.               dummy_xref->lo_text.type = LO_TEXT;
  4512.  
  4513.               /* this is problematic -- what if the anchor has been destroyed? */
  4514.               dummy_xref->lo_text.anchor_href = last_documented_anchor_data;
  4515.               dummy_xref->lo_text.text = dummy_xref->lo_text.anchor_href->anchor;
  4516.  
  4517.               event = XP_NEW_ZAP(JSEvent);
  4518.               event->type = EVENT_MOUSEOUT;
  4519.               event->x = layer_event->x;
  4520.               event->y = layer_event->y;
  4521.               {
  4522.                 fe_EventStruct* e=(fe_EventStruct*)layer_event->fe_event;
  4523.                 event->screenx=e->compressedEvent.pos.root.x;
  4524.                 event->screeny=e->compressedEvent.pos.root.y;
  4525.               }
  4526.               if (layer) {
  4527.                 event->docx = layer_event->x + CL_GetLayerXOrigin(layer);
  4528.                 event->docy = layer_event->y + CL_GetLayerYOrigin(layer);
  4529.               }
  4530.               else {
  4531.                 event->docx = layer_event->x;
  4532.                 event->docy = layer_event->y;
  4533.               }
  4534.  
  4535.               if (m_isImage) {
  4536.                   fe_HTMLViewTooltipsEH(context, layer,    layer_event, 2);
  4537.               }/* if */
  4538.               
  4539. #ifdef DEBUG_spence
  4540.               printf ("Sending MouseOut\n");
  4541. #endif
  4542.               ET_SendEvent (last_documented_xref_context, dummy_xref,
  4543.                             event, fe_mouse_over_callback, NULL);
  4544.           }
  4545.  
  4546.       if (CONTEXT_DATA (context)->active_url_count == 0) {
  4547.           /* If there are transfers in progress, don't document the URL under
  4548.              the mouse, since that message would interfere with the transfer
  4549.              messages.  Do change the cursor, however. */
  4550.           XP_Bool used = False;
  4551.           if (anchor_data) {
  4552.               if (anchor_data != last_documented_anchor_data) {
  4553.                   JSEvent *event;
  4554.                   LO_Element *dummy_xref = (LO_Element *) XP_NEW_ZAP (LO_Element);
  4555.  
  4556.                   XP_MEMSET (dummy_xref, 0, sizeof (LO_Element));
  4557.  
  4558.                   dummy_xref->lo_text.type = LO_TEXT;
  4559.                   dummy_xref->lo_text.anchor_href = anchor_data;
  4560.  
  4561.                   /* we use the text of the element to determine if it is still
  4562.                      valid later so give the dummy text struct's text a value.
  4563.                      */
  4564.                   dummy_xref->lo_text.text = anchor_data->anchor;
  4565.                   
  4566.                   /* just tell mocha - nothing else to do? */
  4567.                   event = XP_NEW_ZAP(JSEvent);
  4568.                   event->type = EVENT_MOUSEOVER;
  4569.  
  4570.                   /* get a valid layer id */
  4571.                   event->layer_id = LO_GetIdFromLayer (context, layer);
  4572.  
  4573.                   event->x = layer_event->x;
  4574.                   event->y = layer_event->y;
  4575.                   {
  4576.                     fe_EventStruct* e=(fe_EventStruct*)layer_event->fe_event;
  4577.                     event->screenx=e->compressedEvent.pos.root.x;
  4578.                     event->screeny=e->compressedEvent.pos.root.y;
  4579.                   }
  4580.  
  4581.                   if (layer) {
  4582.                     event->docx = layer_event->x + CL_GetLayerXOrigin(layer);
  4583.                     event->docy = layer_event->y + CL_GetLayerYOrigin(layer);
  4584.                   }
  4585.                   else {
  4586.                     event->docx = layer_event->x;
  4587.                     event->docy = layer_event->y;
  4588.                   }
  4589.  
  4590.                   if (m_isImage) {
  4591.                       fe_HTMLViewTooltipsEH(context, layer,    layer_event, 3);
  4592.                   }/* if */
  4593. #ifdef DEBUG_spence
  4594.                   printf ("Sending MouseOver\n");
  4595. #endif
  4596.                   ET_SendEvent (context, dummy_xref, event,
  4597.                                 fe_mouse_over_callback, NULL);
  4598.               }
  4599.               else
  4600.                   /* Dont update url too as we haven't moved to a new AREA */
  4601.                   used = True;
  4602.           } 
  4603. #if 0
  4604.           else {
  4605.               printf ("anchor_data == NULL\n");
  4606.           }
  4607. #endif
  4608.  
  4609.     if (!used)
  4610.         fe_MidTruncatedProgress (context, (xref ? url : ""));
  4611.       }
  4612.       
  4613.       last_documented_xref_context = context;
  4614.       last_documented_xref = xref;
  4615.       last_documented_anchor_data = anchor_data;
  4616.  
  4617.       fe_SetCursor (top, !!xref);
  4618.     }
  4619. }
  4620.  
  4621. /* Invoked via a translation on <Btn3Down>
  4622.  */
  4623. void
  4624. fe_extend_selection_action (Widget widget, XEvent *event,
  4625.                 String *av, Cardinal *ac)
  4626. {
  4627.   MWContext *context = fe_MotionWidgetToMWContext (widget);
  4628.   CL_Event layer_event;
  4629.   fe_EventStruct fe_event;
  4630.  
  4631.   XP_ASSERT (context);
  4632.   if (!context) return;
  4633.  
  4634.   if (auto_scroll_timer)
  4635.     {
  4636.       XtRemoveTimeOut (auto_scroll_timer);
  4637.       auto_scroll_timer = 0;
  4638.     }
  4639.  
  4640.   fe_UserActivity (context);
  4641.  
  4642.   fe_NeutralizeFocus (context);
  4643.  
  4644.   /* Fill in FE part of layer_event. */
  4645. #ifdef LAYERS_FULL_FE_EVENT
  4646.   fe_event.event = event;
  4647.   fe_event.av = av;
  4648.   fe_event.ac = ac;
  4649.   fe_event.mouse_action = FE_EXTEND_SELECTION;
  4650. #else
  4651.   fe_event_stuff(context,&fe_event,event,av,ac,FE_EXTEND_SELECTION);
  4652.   layer_event.fe_event_size = sizeof(fe_event);
  4653. #endif
  4654.   layer_event.fe_event = (void *)&fe_event;
  4655.  
  4656.   layer_event.type = CL_EVENT_MOUSE_BUTTON_DOWN;
  4657.   layer_event.which = event->xbutton.button;
  4658.   layer_event.modifiers = xfeToLayerModifiers(event->xbutton.state);
  4659.  
  4660.   if (context->compositor)
  4661.       {
  4662.           unsigned long x, y;
  4663.  
  4664.           fe_EventLOCoords (context, event, &x, &y);
  4665.           layer_event.x = x;
  4666.           layer_event.y = y;
  4667.           CL_DispatchEvent(context->compositor, &layer_event);
  4668.       }
  4669.   else
  4670.       {
  4671.           fe_extend_selection_action_for_layer(context, NULL, &layer_event);
  4672.       }
  4673. }
  4674.  
  4675. /* Layer specific actions.  fe_extend_selection_action() */
  4676. void
  4677. fe_extend_selection_action_for_layer(MWContext *context, CL_Layer *layer,
  4678.                                      CL_Event *layer_event)
  4679. {
  4680.   Time time;
  4681.   unsigned long x, y;
  4682.  
  4683.   /* Note that the av and ac parameters that were passed to 
  4684.      fe_extend_selection_action() can be obtained from the 
  4685.      fe_event structure. */
  4686.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  4687. #ifdef LAYERS_FULL_FE_EVENT
  4688.   XEvent *event = fe_event->event;
  4689. #else
  4690.   XEvent *event = fe_event_extract(fe_event,NULL,NULL,NULL);
  4691. #endif
  4692.  
  4693.   time = (event && (event->type == KeyPress ||
  4694.             event->type == KeyRelease)
  4695.       ? event->xkey.time :
  4696.       event && (event->type == ButtonPress ||
  4697.             event->type == ButtonRelease)
  4698.       ? event->xbutton.time :
  4699.       XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  4700.  
  4701.   x = layer_event->x;
  4702.   y = layer_event->y;
  4703.  
  4704.   LO_ExtendSelection (context, x, y);
  4705.   fe_OwnSelection (context, time, False);
  4706.  
  4707.   /* Making a selection turns off "Save Next" mode. */
  4708.   if (CONTEXT_DATA (context)->save_next_mode_p)
  4709.     {
  4710.       XBell (XtDisplay (CONTEXT_WIDGET(context)), 0);
  4711.       CONTEXT_DATA (context)->save_next_mode_p = False;
  4712.       fe_SetCursor (context, False);
  4713.       XFE_Progress (context, fe_globalData.click_to_save_cancelled_message);
  4714.     }
  4715. }
  4716.  
  4717.  
  4718. #ifdef DEBUG_francis
  4719. static void printKeyEvent(XEvent* event)
  4720. {
  4721.   if (!(   ((event->xany.type)==KeyPress)
  4722.     || ((event->xany.type)==KeyRelease)
  4723.     )
  4724.       )
  4725.     {
  4726.       printf("{non-key event}\n");
  4727.       return;
  4728.     }
  4729.  
  4730.   printf("{key event:\n"
  4731.      "\tserial==%u\n"
  4732.      "\tsend_event==%s\n"
  4733.      "\tdisplay==0x%x\n"
  4734.      "\twindow==0x%x\n"
  4735.      "\troot==0x%x\n"
  4736.      "\tsubwindow==0x%x\n"
  4737.      "\ttime==0x%x\n"
  4738.      "\t(x,y)==(%d,%d)\n"
  4739.      "\t(x_root,y_root)==(%d,%d)\n"
  4740.      "\tstate==%d\n"
  4741.      "\tkeycode==%d\n"
  4742.      "\tsame_screen==%s}\n",
  4743.      event->xkey.serial,
  4744.      (event->xkey.send_event ? "true" : "false"),
  4745.      event->xkey.display,
  4746.      event->xkey.window,
  4747.      event->xkey.root,
  4748.      event->xkey.subwindow,
  4749.      event->xkey.time,
  4750.      event->xkey.x,event->xkey.y,
  4751.      event->xkey.x_root,event->xkey.y_root,
  4752.      event->xkey.state,event->xkey.keycode,
  4753.      (event->xkey.same_screen ? "true" : "false")
  4754.      );
  4755. }
  4756. #endif
  4757.  
  4758. static XP_Bool keyStates[65536];
  4759. static XP_Bool keyStatesInited=False;
  4760.  
  4761. static void keyStatesInit(void)
  4762. {
  4763.   if (keyStatesInited)
  4764.     return;
  4765.   memset(keyStates,0,sizeof(keyStates));
  4766.   keyStatesInited=True;
  4767. }
  4768.  
  4769. static XP_Bool keyStatesDown(int keycode)
  4770. {
  4771.   if ((keycode<0) || (keycode>=65536))
  4772.     return 0;
  4773.  
  4774.   keyStatesInit();
  4775.  
  4776.   {
  4777.     XP_Bool res=keyStates[keycode];
  4778.     keyStates[keycode]=1;
  4779.     return res;
  4780.   }
  4781. }
  4782.  
  4783. static XP_Bool keyStatesUp(int keycode)
  4784. {
  4785.   if ((keycode<0) || (keycode>=65536))
  4786.     return 0;
  4787.  
  4788.   keyStatesInit();
  4789.  
  4790.   {
  4791.     XP_Bool res=keyStates[keycode];
  4792.     keyStates[keycode]=0;
  4793.     return res;
  4794.   }
  4795. }
  4796.  
  4797. static void fe_key_up_in_text_action(Widget widget,
  4798.                      XEvent *event,
  4799.                      String *av, Cardinal *ac)
  4800. {
  4801.   MWContext *context = fe_WidgetToMWContext (widget);
  4802.   CL_Event layer_event;
  4803.   fe_EventStruct fe_event;
  4804.  
  4805.   XP_ASSERT (context);
  4806.   if (!context) return;
  4807.  
  4808.   /* Fill in FE part of layer_event. */
  4809. #ifdef LAYERS_FULL_FE_EVENT
  4810.   fe_event.event = event;
  4811.   fe_event.av = av;
  4812.   fe_event.ac = ac;
  4813.   fe_event.mouse_action = FE_KEY_UP;
  4814. #else
  4815.   fe_event_stuff(context,&fe_event,event,av,ac,FE_KEY_UP);
  4816.   layer_event.fe_event_size = sizeof(fe_event);
  4817.  
  4818.   fe_event.data=widget;
  4819. #endif
  4820.  
  4821.   layer_event.fe_event = (void *)&fe_event;
  4822.  
  4823.   layer_event.type = CL_EVENT_KEY_UP;
  4824.   layer_event.which = xfeKeycodeToWhich(event->xkey.keycode,
  4825.                                         event->xkey.state);
  4826.   layer_event.modifiers = xfeToLayerModifiers(event->xkey.state);
  4827.  
  4828.   if (context->compositor)
  4829.       {
  4830.           unsigned long x, y;
  4831.  
  4832.           fe_EventLOCoords (context, event, &x, &y);
  4833.           layer_event.x = x;
  4834.           layer_event.y = y;
  4835.           CL_DispatchEvent(context->compositor, &layer_event);
  4836.       }
  4837.   else
  4838.       {
  4839.           fe_key_up_in_text_action_for_layer(context, NULL, &layer_event);
  4840.       }
  4841. }
  4842.  
  4843. /* Layer specific actions.  fe_extend_selection_action() */
  4844. void
  4845. fe_key_up_in_text_action_for_layer(MWContext *context, CL_Layer *layer,
  4846.                    CL_Event *layer_event)
  4847. {
  4848.   Time time;
  4849.   unsigned long x, y;
  4850.   /* Note that the av and ac parameters that were passed to 
  4851.      fe_extend_selection_action() can be obtained from the 
  4852.      fe_event structure. */
  4853.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  4854. #ifndef LAYERS_FULL_FE_EVENT
  4855.   XEvent *event = fe_event_extract(fe_event,NULL,NULL,NULL);
  4856.   Widget widget=(Widget)fe_event->data;
  4857. #endif
  4858.  
  4859.   time = (event && (event->type == KeyPress ||
  4860.             event->type == KeyRelease)
  4861.       ? event->xkey.time :
  4862.       event && (event->type == ButtonPress ||
  4863.             event->type == ButtonRelease)
  4864.       ? event->xbutton.time :
  4865.       XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  4866.  
  4867.   x = layer_event->x;
  4868.   y = layer_event->y;
  4869.  
  4870.   {
  4871.     LO_Element* text=fe_text_of_widget(context, widget, layer);
  4872.  
  4873.     keyStatesUp(layer_event->which);
  4874.     
  4875.     {
  4876.       JSEvent *jsevent = (JSEvent*)XP_NEW_ZAP(JSEvent);
  4877.  
  4878.       jsevent->type = EVENT_KEYUP;
  4879.  
  4880.       jsevent->x = layer_event->x;
  4881.       jsevent->y = layer_event->y;
  4882.       if (layer) {
  4883.     jsevent->docx = layer_event->x + CL_GetLayerXOrigin(layer);
  4884.     jsevent->docy = layer_event->y + CL_GetLayerYOrigin(layer);
  4885.       }
  4886.       else {
  4887.     jsevent->docx = layer_event->x;
  4888.     jsevent->docy = layer_event->y;
  4889.       }
  4890.       jsevent->which = layer_event->which;
  4891.       jsevent->modifiers = layer_event->modifiers;
  4892.       jsevent->screenx = event->xbutton.x_root;
  4893.       jsevent->screeny = event->xbutton.y_root;
  4894.       
  4895.       ET_SendEvent (context, text,
  4896.             jsevent,
  4897.             NULL, NULL);
  4898.     }
  4899.   }
  4900. }
  4901.  
  4902. typedef struct {
  4903.   Widget widget;
  4904.   fe_EventStruct evt;
  4905.   int newInsertionPoint;
  4906. } KeydownClosure;
  4907.  
  4908. static int fe_textModifyVerifyCallbackInhibited=0;
  4909.  
  4910. int fe_isTextModifyVerifyCallbackInhibited(void)
  4911. {
  4912.   return fe_textModifyVerifyCallbackInhibited;
  4913. }
  4914.  
  4915. static int fe_textModifyVerifyCallbackNewInsertionPoint=-1;
  4916.  
  4917. static void finish_keydown(void* _closure)
  4918. {
  4919.   KeydownClosure* closure=(KeydownClosure*)_closure;
  4920.   String* av;
  4921.   Cardinal* ac;
  4922.   XEvent *event = fe_event_extract(&(closure->evt),&av,&ac,NULL);
  4923.   KeySym keysym=xfeKeycodeToWhich(event->xkey.keycode,
  4924.                   event->xkey.state);
  4925.   
  4926.   fe_textModifyVerifyCallbackInhibited++;
  4927.   if ((closure->newInsertionPoint)<0)
  4928.     XtCallActionProc(closure->widget,
  4929.              (  (keysym==XK_Return)
  4930.               ? "process-return"
  4931.               : "self-insert"
  4932.               ),
  4933.              event,
  4934.              av,*ac);
  4935.   else
  4936.     XmTextSetInsertionPosition(closure->widget,
  4937.                    closure->newInsertionPoint);
  4938.   fe_textModifyVerifyCallbackInhibited--;
  4939.   XP_FREE(closure);
  4940. }
  4941.  
  4942. static void fe_mocha_handle_keydown(MWContext* context,
  4943.                     LO_Element* element,
  4944.                     int32 _event,
  4945.                     void* closure,
  4946.                     ETEventStatus status)
  4947. {
  4948.   if (status == EVENT_OK)
  4949.     finish_keydown(closure);
  4950.   else
  4951.     XP_FREE(closure);
  4952. }
  4953.  
  4954. static void fe_key_down_in_text_action(Widget widget,
  4955.                        XEvent *event,
  4956.                        String *av, Cardinal *ac)
  4957. {
  4958.   MWContext *context = fe_WidgetToMWContext (widget);
  4959.   CL_Event layer_event;
  4960.   fe_EventStruct fe_event;
  4961.  
  4962.   XP_ASSERT (context);
  4963.   if (!context) return;
  4964.  
  4965.   /* Fill in FE part of layer_event. */
  4966. #ifdef LAYERS_FULL_FE_EVENT
  4967.   fe_event.event = event;
  4968.   fe_event.av = av;
  4969.   fe_event.ac = ac;
  4970.   fe_event.mouse_action = FE_KEY_DOWN;
  4971.   fe_event.data=widget;
  4972. #else
  4973.   fe_event_stuff(context,&fe_event,event,av,ac,FE_KEY_DOWN);
  4974.   fe_event.data=widget;
  4975.   layer_event.fe_event_size = sizeof(fe_event);
  4976.  
  4977. #endif
  4978.   layer_event.fe_event = (void *)&fe_event;
  4979.  
  4980.   layer_event.type = CL_EVENT_KEY_DOWN;
  4981.   layer_event.which = xfeKeycodeToWhich(event->xkey.keycode,
  4982.                                         event->xkey.state);
  4983.   layer_event.modifiers = xfeToLayerModifiers(event->xkey.state);
  4984.  
  4985.   if (context->compositor)
  4986.     {
  4987.       unsigned long x, y;
  4988.  
  4989.       fe_EventLOCoords (context, event, &x, &y);
  4990.       layer_event.x = x;
  4991.       layer_event.y = y;
  4992.       CL_DispatchEvent(context->compositor, &layer_event);
  4993.     }
  4994.   else
  4995.     {
  4996.       fe_key_down_in_text_action_for_layer(context, NULL, &layer_event);
  4997.     }
  4998. }
  4999.  
  5000. /* Layer specific actions.  fe_extend_selection_action() */
  5001. void
  5002. fe_key_down_in_text_action_for_layer(MWContext *context, CL_Layer *layer,
  5003.                      CL_Event *layer_event)
  5004. {
  5005.   Time time;
  5006.   unsigned long x, y;
  5007.   /* Note that the av and ac parameters that were passed to 
  5008.      fe_extend_selection_action() can be obtained from the 
  5009.      fe_event structure. */
  5010.   fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  5011. #ifndef LAYERS_FULL_FE_EVENT
  5012.   String *av;
  5013.   Cardinal *ac;
  5014.   XEvent *event = fe_event_extract(fe_event,&av,&ac,NULL);
  5015.   Widget widget=(Widget)fe_event->data;
  5016. #endif
  5017.  
  5018.   time = (event && (event->type == KeyPress ||
  5019.             event->type == KeyRelease)
  5020.       ? event->xkey.time :
  5021.       event && (event->type == ButtonPress ||
  5022.             event->type == ButtonRelease)
  5023.       ? event->xbutton.time :
  5024.       XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  5025.  
  5026.   x = layer_event->x;
  5027.   y = layer_event->y;
  5028.  
  5029.   {
  5030.     LO_Element* text=fe_text_of_widget(context, widget, layer);
  5031.     KeydownClosure* closure=XP_NEW_ZAP(KeydownClosure);
  5032.  
  5033.     closure->widget=widget;
  5034.     closure->evt=(*fe_event);
  5035.  
  5036. #if 0
  5037.     if ((*ac)==2)
  5038.       sscanf(av[1],"%d",&(closure->newInsertionPoint));
  5039.     else
  5040.       closure->newInsertionPoint=-1;
  5041. #else
  5042.     closure->newInsertionPoint=fe_textModifyVerifyCallbackNewInsertionPoint;
  5043. #endif
  5044.  
  5045.     {
  5046.       JSEvent *jsevent = XP_NEW_ZAP(JSEvent);
  5047.  
  5048.       jsevent->type = (  keyStatesDown(layer_event->which)
  5049.                ? EVENT_KEYPRESS
  5050.                : EVENT_KEYDOWN
  5051.                );
  5052.  
  5053.       jsevent->x = layer_event->x;
  5054.       jsevent->y = layer_event->y;
  5055.       if (layer) {
  5056.     jsevent->docx = layer_event->x + CL_GetLayerXOrigin(layer);
  5057.     jsevent->docy = layer_event->y + CL_GetLayerYOrigin(layer);
  5058.       }
  5059.       else {
  5060.     jsevent->docx = layer_event->x;
  5061.     jsevent->docy = layer_event->y;
  5062.       }
  5063.       jsevent->which = layer_event->which;
  5064.       jsevent->modifiers = layer_event->modifiers;
  5065.       jsevent->screenx = event->xbutton.x_root;
  5066.       jsevent->screeny = event->xbutton.y_root;
  5067.       
  5068.       ET_SendEvent (context, text,
  5069.             jsevent, fe_mocha_handle_keydown,
  5070.             closure);
  5071.     }
  5072.   }
  5073.  
  5074. }
  5075.  
  5076. void fe_textModifyVerifyCallback(Widget w,
  5077.                                  XtPointer closure,
  5078.                                  XtPointer call_data)
  5079. {
  5080.   if (!fe_textModifyVerifyCallbackInhibited)
  5081.     {
  5082.       XmTextVerifyCallbackStruct* cbs=(XmTextVerifyCallbackStruct*)call_data;
  5083.       XEvent* event=cbs->event;
  5084.       if (   event
  5085.           && (event->type==KeyPress)
  5086.           && (cbs->text)
  5087.           && ((cbs->text->length)==1)
  5088.           )
  5089.         {
  5090.           cbs->doit=False;
  5091.           fe_textModifyVerifyCallbackNewInsertionPoint=-1;
  5092.           fe_key_down_in_text_action(w,event,NULL,NULL);
  5093.         }
  5094.       else
  5095.         {
  5096.           fe_textModifyVerifyCallbackInhibited++;
  5097.           XtCallCallbacks(w,XmNmodifyVerifyCallback,call_data);
  5098.           fe_textModifyVerifyCallbackInhibited--;
  5099.         }
  5100.     }
  5101. }
  5102.  
  5103. void fe_textMotionVerifyCallback(Widget w,
  5104.                  XtPointer closure,
  5105.                  XtPointer call_data)
  5106. {
  5107.   if (!fe_textModifyVerifyCallbackInhibited)
  5108.     {
  5109.       XmTextVerifyCallbackStruct* cbs=(XmTextVerifyCallbackStruct*)call_data;
  5110.       XEvent* event=cbs->event;
  5111.       if (   event
  5112.       && (event->type==KeyPress)
  5113.       )
  5114.     {
  5115. #if 0
  5116.       char* buff=malloc(20);
  5117.       String argv[3]={"motion",buff,0};
  5118.       Cardinal argc=2;
  5119.       sprintf(buff,"%d",cbs->newInsert);
  5120. #endif
  5121.       cbs->doit=False;
  5122.       fe_textModifyVerifyCallbackNewInsertionPoint=cbs->newInsert;
  5123.       fe_key_down_in_text_action(w,event,
  5124. #if 0
  5125.                      argv,&argc
  5126. #else
  5127.                      NULL,NULL
  5128. #endif
  5129.                      );
  5130.     }
  5131.     }
  5132. }
  5133.  
  5134.  
  5135.  
  5136. static XtActionsRec fe_mouse_actions [] =
  5137. {
  5138.   { "ArmLink",         fe_arm_link_action },
  5139.   { "DisarmLink",     fe_disarm_link_action },
  5140.   { "ActivateLink",     fe_activate_link_action },
  5141.   { "DisarmLinkIfMoved", fe_disarm_link_if_moved_action },
  5142.   { "ExtendSelection",     fe_extend_selection_action },
  5143.   { "DescribeLink",     fe_describe_link_action }
  5144. };
  5145.  
  5146. void
  5147. fe_InitMouseActions ()
  5148. {
  5149.   XtAppAddActions (fe_XtAppContext, fe_mouse_actions,
  5150.            countof (fe_mouse_actions));
  5151. }
  5152.  
  5153. static XtActionsRec fe_key_actions [] =
  5154. {
  5155.   { "KeyUpInText",     fe_key_up_in_text_action }
  5156. /*,
  5157.   { "KeyDownInText",     fe_key_down_in_text_action }*/
  5158. };
  5159.  
  5160. void
  5161. fe_InitKeyActions ()
  5162. {
  5163.   XtAppAddActions (fe_XtAppContext, fe_key_actions,
  5164.            countof (fe_key_actions));
  5165. }
  5166.  
  5167. static ContextFuncs _xfe_funcs = {
  5168. #define FE_DEFINE(func, returns, args) XFE##_##func,
  5169. #include "mk_cx_fn.h"
  5170. };
  5171.  
  5172. ContextFuncs *
  5173. fe_BuildDisplayFunctionTable(void)
  5174. {
  5175.     return &_xfe_funcs;
  5176. }
  5177.  
  5178. void
  5179. FE_LoadGridCellFromHistory(MWContext *context, void *hist,
  5180.                NET_ReloadMethod force_reload)
  5181. {
  5182.   History_entry *he = (History_entry *)hist;
  5183.   URL_Struct *url;
  5184.  
  5185.   if (! he) return;
  5186.   url = SHIST_CreateURLStructFromHistoryEntry (context, he);
  5187.   url->force_reload = force_reload;
  5188.   fe_GetURL (context, url, FALSE);
  5189. }
  5190.  
  5191. void *
  5192. FE_FreeGridWindow(MWContext *context, XP_Bool save_history)
  5193. {
  5194.   LO_Element *e;
  5195.   History_entry *he;
  5196.   XP_List *hist_list;
  5197.  
  5198.   hist_list = NULL;
  5199.   he = NULL;
  5200.   if ((context)&&(context->is_grid_cell))
  5201.     {
  5202.       /* remove focus from this grid */
  5203.       CONTEXT_DATA (context)->focus_grid = False;
  5204.  
  5205.       /*
  5206.        * If we are going to save the history of this grid cell
  5207.        * we need to stuff the last scroll position into the
  5208.        * history structure, and then remove that structure
  5209.        * from its linked list so it won't be freed when the
  5210.        * context is destroyed.
  5211.        */
  5212.       if (save_history)
  5213.         {
  5214.           e = LO_XYToNearestElement (context,
  5215.                                      CONTEXT_DATA (context)->document_x,
  5216.                                      CONTEXT_DATA (context)->document_y,
  5217.                                      NULL);
  5218.           he = SHIST_GetCurrent (&context->hist);
  5219.           if (e)
  5220.             SHIST_SetPositionOfCurrentDoc (&context->hist, e->lo_any.ele_id);
  5221.  
  5222.       hist_list = context->hist.list_ptr;
  5223.       context->hist.list_ptr = NULL;
  5224.         }
  5225.  
  5226.       fe_DestroyContext(context);
  5227.     }
  5228.   return(hist_list);
  5229. }
  5230.  
  5231. void XFE_GetTextFrame(MWContext *context, LO_TextStruct *text, int32 start,
  5232.                       int32 end, XP_Rect *frame)
  5233. {
  5234.     LO_TextAttr * attr = text->text_attr;
  5235.     fe_Font font;
  5236.     int L, remaining, width, height, ascent, descent;
  5237.     char *str;
  5238.     XCharStruct overall;
  5239.  
  5240.     font = fe_LoadFontFromFace (context, attr, &attr->charset,
  5241.                                 attr->font_face, attr->size, attr->fontmask);
  5242.     frame->left = text->x + text->x_offset;
  5243.     frame->top = text->y + text->y_offset;
  5244.  
  5245.   /* X is such a winner, it uses 16 bit quantities to represent all pixel
  5246.      widths.  This is really swell, because it means that if you've got
  5247.      a large font, you can't correctly compute the size of strings which
  5248.      are only a few thousand characters long.  So, when the string is more
  5249.      than N characters long, we divide up our calls to XTextExtents to
  5250.      keep the size down so that the library doesn't run out of fingers
  5251.      and toes.
  5252.    */
  5253. #define SUCKY_X_MAX_LENGTH 600
  5254.  
  5255.     XP_ASSERT(font);              /* Should really return FALSE on failure. */
  5256.  
  5257.     str = (char *) text->text;
  5258.     remaining = start;
  5259.     width = 0;
  5260.     height = 0;
  5261.     do
  5262.         {
  5263.             L = (remaining > SUCKY_X_MAX_LENGTH ? SUCKY_X_MAX_LENGTH :
  5264.                  remaining);
  5265.             FE_TEXT_EXTENTS (attr->charset, font, str, L,
  5266.                              &ascent, &descent, &overall);
  5267.             width += overall.width;
  5268.             height = MAX(height, ascent + descent);
  5269.             str += L;
  5270.             remaining -= L;
  5271.         }
  5272.     while (remaining > 0);
  5273.     frame->left += width;
  5274.  
  5275.     str = (char *) text->text + start;
  5276.     remaining = end - start + 1;
  5277.     width = 0;
  5278.     do
  5279.         {
  5280.             L = (remaining > SUCKY_X_MAX_LENGTH ? SUCKY_X_MAX_LENGTH :
  5281.                  remaining);
  5282.             FE_TEXT_EXTENTS (attr->charset, font, str, L,
  5283.                              &ascent, &descent, &overall);
  5284.             width += overall.width;
  5285.             height = MAX(height, ascent + descent);
  5286.             str += L;
  5287.             remaining -= L;
  5288.         }
  5289.     while (remaining > 0);
  5290.     frame->right = frame->left + width;
  5291.     frame->bottom = frame->top + height;
  5292. }
  5293.  
  5294. /* Display a border.  x, y, width and height specify the outer perimeter of the
  5295.    border. */
  5296. void
  5297. XFE_DisplayBorder(MWContext *context, int iLocation, int x, int y, int width,
  5298.                   int height, int bw, LO_Color *color, LO_LineStyle style) 
  5299. {
  5300.     fe_Drawable *fe_drawable = CONTEXT_DATA(context)->drawable;
  5301.     Drawable drawable = fe_drawable->xdrawable;
  5302.     Widget widget = CONTEXT_WIDGET(context);
  5303.     Display *dpy = XtDisplay(widget);
  5304.  
  5305.     if (bw > 0) {
  5306.         GC gc;
  5307.         XGCValues gcv;
  5308.         unsigned long flags;
  5309.  
  5310.         memset (&gcv, ~0, sizeof (gcv));
  5311.         gcv.function = GXcopy;
  5312.         gcv.foreground = fe_GetPixel (context, color->red, color->green,
  5313.                                       color->blue);
  5314.         gcv.line_width = bw;
  5315.         flags = GCFunction | GCForeground | GCLineWidth;
  5316.         gc = fe_GetGCfromDW (dpy, drawable, flags, &gcv,
  5317.                              fe_drawable->clip_region);
  5318.  
  5319.         /* Add in the layer origin. */
  5320.         x += fe_drawable->x_origin - CONTEXT_DATA(context)->document_x;
  5321.         y += fe_drawable->y_origin - CONTEXT_DATA(context)->document_y;
  5322.  
  5323.         switch (style) {
  5324.         case LO_SOLID:
  5325.             /* Beware: XDrawRectangle centers the line-thickness on the
  5326.                coords. */
  5327.             XDrawRectangle (dpy, drawable, gc, x + (bw / 2), y + (bw / 2),
  5328.                             width - bw, height - bw);
  5329.             break;
  5330.             
  5331.         case LO_BEVEL:
  5332.             fe_DrawShadows (context, fe_drawable, x, y, width, height, bw,
  5333.                             XmSHADOW_IN);
  5334.             break;
  5335.  
  5336.         default:
  5337.             break;
  5338.         }
  5339.     }
  5340. }
  5341.  
  5342. static void
  5343. xfe_display_image_feedback(MWContext* context, LO_ImageStruct* lo_image)
  5344. {
  5345.     Display*     display;
  5346.     fe_Drawable* fe_drawable;
  5347.     Drawable     drawable;
  5348.     XGCValues    gcv;
  5349.     GC           gc;
  5350.     int          x;
  5351.     int          y;
  5352.     unsigned     w;
  5353.     unsigned     h;
  5354.     unsigned     bw;
  5355.  
  5356. #ifdef EDITOR
  5357.     /*
  5358.      *    Draw selection effects.
  5359.      */
  5360.     if (EDT_IS_EDITOR(context) && /* still only for editor in 4.0? */
  5361.         (lo_image->ele_attrmask & LO_ELE_SELECTED) != 0) {
  5362.  
  5363.         display = XtDisplay(CONTEXT_DATA(context)->drawing_area);
  5364.         fe_drawable = CONTEXT_DATA(context)->drawable;
  5365.         drawable = fe_drawable->xdrawable;
  5366.  
  5367.         memset(&gcv, ~0, sizeof (gcv));
  5368.         gcv.foreground = CONTEXT_DATA(context)->fg_pixel;
  5369.         gcv.background = CONTEXT_DATA(context)->select_bg_pixel;
  5370.         gcv.line_width = 1;
  5371.         gcv.line_style = LineDoubleDash;
  5372.         gc = fe_GetGCfromDW(display, drawable,
  5373.                             GCForeground|GCBackground|GCLineStyle|GCLineWidth,
  5374.                             &gcv,
  5375.                             fe_drawable->clip_region);
  5376.  
  5377.         bw = lo_image->border_width;
  5378.         x = fe_drawable->x_origin - CONTEXT_DATA(context)->document_x +
  5379.             lo_image->x + lo_image->x_offset;
  5380.  
  5381.         y = fe_drawable->y_origin - CONTEXT_DATA(context)->document_y +
  5382.             lo_image->y + lo_image->y_offset;
  5383.         w = lo_image->width  + bw + bw;
  5384.         h = lo_image->height + bw + bw;
  5385.  
  5386.         /* beware: XDrawRectangle centers the line-thickness on the coords. */
  5387.         XDrawRectangle(display, drawable,
  5388.                        gc, x, y, (w - gcv.line_width), (h - gcv.line_width));
  5389.     }
  5390. #endif /*EDITOR*/
  5391.  
  5392.     /*
  5393.      *    Tab navigation.
  5394.      */
  5395. }
  5396.  
  5397. /* Display feedback about a layout element e.g. editor selection, tab navigation
  5398.    highlighting, etc. */
  5399. void
  5400. XFE_DisplayFeedback(MWContext *context, int iLocation, LO_Element *element)
  5401. {
  5402.     if (element->lo_any.type == LO_IMAGE ) {
  5403.         xfe_display_image_feedback(context, (LO_ImageStruct*)element);
  5404.     }
  5405.  
  5406.     /* XXX Implement me. */
  5407. }
  5408.  
  5409. #ifndef LAYERS_FULL_FE_EVENT
  5410.  
  5411. static fe_EventActivateKind calcActivateKind(const String* av,
  5412.                          const Cardinal* ac,
  5413.                          fe_MouseActionEnum mouse_action)
  5414. {
  5415.   if (mouse_action!=FE_ACTIVATE_LINK)
  5416.     return fe_EventActivateKindNone;
  5417.  
  5418.   if (!(av && ac))
  5419.     return fe_EventActivateKindNone;
  5420.  
  5421.   {
  5422.     int N=*ac;
  5423.  
  5424.     if (N>2)
  5425.       {
  5426.     fprintf (stderr, 
  5427.              XP_GetString(XFE_LAY_TOO_MANY_ARGS_TO_ACTIVATE_LINK_ACTION),
  5428.          fe_progname, *ac);
  5429.     return fe_EventActivateKindNone;
  5430.       }
  5431.       
  5432.     if (N==0)
  5433.       return fe_EventActivateKindNormal;
  5434.  
  5435.     if (N==1)
  5436.       {
  5437.     if (!strcmp ("new-window", av[0]))
  5438.       return fe_EventActivateKindNewWindow;
  5439.  
  5440.     if (!strcmp ("save-only", av[0]))
  5441.       return fe_EventActivateKindSaveOnly;
  5442.       }
  5443.   }
  5444.  
  5445.   fprintf (stderr,
  5446.            XP_GetString(XFE_LAY_UNKNOWN_PARAMETER_TO_ACTIVATE_LINK_ACTION),
  5447.        fe_progname, av[0]);
  5448.   return fe_EventActivateKindNone;
  5449. }
  5450.  
  5451. static String* invertActivateKind(fe_EventActivateKind kind)
  5452. {
  5453.   static String res;
  5454.  
  5455.   switch (kind)
  5456.     {
  5457.     case fe_EventActivateKindSaveOnly:
  5458.       res="save-only";
  5459.       return &res;
  5460.  
  5461.     case fe_EventActivateKindNewWindow:
  5462.       res="new-window";
  5463.       return &res;
  5464.  
  5465.     case fe_EventActivateKindNone:
  5466.     case fe_EventActivateKindNormal:
  5467.     default:
  5468.       return NULL;
  5469.     }
  5470. }
  5471.  
  5472. void fe_event_stuff(MWContext* context,
  5473.             fe_EventStruct* fe_event,
  5474.             const XEvent* event,
  5475.             const String* av,
  5476.             const Cardinal* ac,
  5477.             fe_MouseActionEnum mouse_action)
  5478. {
  5479.   if (!fe_event)
  5480.     return;
  5481.  
  5482.   fe_event->mouse_action=mouse_action;
  5483.  
  5484.   if (event)
  5485.     {
  5486.       switch (event->type)
  5487.     {
  5488.     case KeyPress:
  5489.     case KeyRelease:
  5490.       if (   (mouse_action==FE_KEY_UP)
  5491.           || (mouse_action==FE_KEY_DOWN)
  5492.           )
  5493.         {
  5494.           fe_event->compressedEvent.pos.win.x=event->xkey.x;
  5495.           fe_event->compressedEvent.pos.win.y=event->xkey.y;
  5496.           fe_event->compressedEvent.pos.root.x=event->xkey.x_root;
  5497.           fe_event->compressedEvent.pos.root.y=event->xkey.y_root;
  5498.           fe_event->compressedEvent.arg.key.state=event->xkey.state;
  5499.           fe_event->compressedEvent.arg.key.keycode=event->xkey.keycode;
  5500.         }
  5501.       else
  5502.         {
  5503.           fe_event->compressedEvent.pos.win.x=
  5504.         fe_event->compressedEvent.pos.win.y=
  5505.           fe_event->compressedEvent.pos.root.x=
  5506.             fe_event->compressedEvent.pos.root.y=
  5507.               0;
  5508.         }
  5509.       fe_event->compressedEvent.time=event->xkey.time;
  5510.       break;
  5511.  
  5512.     case ButtonPress:
  5513.     case ButtonRelease:
  5514.       fe_event->compressedEvent.pos.win.x=event->xbutton.x;
  5515.       fe_event->compressedEvent.pos.win.y=event->xbutton.y;
  5516.       fe_event->compressedEvent.pos.root.x=event->xbutton.x_root;
  5517.       fe_event->compressedEvent.pos.root.y=event->xbutton.y_root;
  5518.       fe_event->compressedEvent.arg.button.root=event->xbutton.root;
  5519.       fe_event->compressedEvent.time=event->xbutton.time;
  5520.       break;
  5521.  
  5522.     case MotionNotify:
  5523.       fe_event->compressedEvent.pos.win.x=event->xmotion.x;
  5524.       fe_event->compressedEvent.pos.win.y=event->xmotion.y;
  5525.       fe_event->compressedEvent.pos.root.x=event->xmotion.x_root;
  5526.       fe_event->compressedEvent.pos.root.y=event->xmotion.y_root;
  5527.       fe_event->compressedEvent.time=0;
  5528.       break;
  5529.  
  5530.     default:
  5531. #ifdef DEBUG
  5532.       fprintf(stderr,
  5533.           "fe_event_stuff(): unsupported XEvent type %d\n",
  5534.           event->type);
  5535. #endif
  5536.       fe_event->compressedEvent.pos.win.x=
  5537.         fe_event->compressedEvent.pos.win.y=
  5538.           fe_event->compressedEvent.pos.root.x=
  5539.         fe_event->compressedEvent.pos.root.y=
  5540.           0;
  5541.       fe_event->compressedEvent.time=0;
  5542.       break;
  5543.     }
  5544.       fe_event->compressedEvent.type=event->type;
  5545.     }
  5546.   else
  5547.     {
  5548.       fe_event->compressedEvent.pos.win.x=
  5549.     fe_event->compressedEvent.pos.win.y=
  5550.       fe_event->compressedEvent.pos.root.x=
  5551.         fe_event->compressedEvent.pos.root.y=
  5552.           0;
  5553.       fe_event->compressedEvent.time=0;
  5554.       fe_event->compressedEvent.type=0;
  5555.     }
  5556.  
  5557.   fe_event->activateKind=calcActivateKind(av,ac,mouse_action);
  5558.   fe_event->data=0;
  5559.  
  5560.   if (context)
  5561.     fe_CacheWindowOffset(context,
  5562.              ( fe_event->compressedEvent.pos.root.x
  5563.               -fe_event->compressedEvent.pos.win.x
  5564.               ),
  5565.              ( fe_event->compressedEvent.pos.root.y
  5566.               -fe_event->compressedEvent.pos.win.y
  5567.               )
  5568.              );
  5569. }
  5570.  
  5571. XEvent* fe_event_extract(const fe_EventStruct* fe_event,
  5572.              String** av,
  5573.              Cardinal** ac,
  5574.              fe_MouseActionEnum* mouse_action)
  5575. {
  5576.   static XEvent event;
  5577.   static Cardinal zero=0;
  5578.  
  5579.   event.xany.display=fe_display;
  5580.  
  5581.   if (!fe_event)
  5582.     {
  5583.       if (av)
  5584.     (*av)=0;
  5585.       if (ac)
  5586.     (*ac)=&zero;
  5587.  
  5588.       if (mouse_action)
  5589.     (*mouse_action)=FE_INVALID_MOUSE_ACTION;
  5590.       return NULL;
  5591.     }
  5592.  
  5593.   event.type=fe_event->compressedEvent.type;
  5594.  
  5595.   switch (event.type)
  5596.     {
  5597.     case KeyPress:
  5598.     case KeyRelease:
  5599.       if (   (fe_event->mouse_action==FE_KEY_UP)
  5600.       || (fe_event->mouse_action==FE_KEY_DOWN)
  5601.       )
  5602.     {
  5603.       event.xkey.x=fe_event->compressedEvent.pos.win.x;
  5604.       event.xkey.y=fe_event->compressedEvent.pos.win.y;
  5605.       event.xkey.x_root=fe_event->compressedEvent.pos.root.x;
  5606.       event.xkey.y_root=fe_event->compressedEvent.pos.root.y;
  5607.       event.xkey.state=fe_event->compressedEvent.arg.key.state;
  5608.       event.xkey.keycode=fe_event->compressedEvent.arg.key.keycode;
  5609.     }
  5610.       event.xkey.time=fe_event->compressedEvent.time;
  5611.       break;
  5612.       
  5613.     case ButtonPress:
  5614.     case ButtonRelease:
  5615.       event.xbutton.x=fe_event->compressedEvent.pos.win.x;
  5616.       event.xbutton.y=fe_event->compressedEvent.pos.win.y;
  5617.       event.xbutton.x_root=fe_event->compressedEvent.pos.root.x;
  5618.       event.xbutton.y_root=fe_event->compressedEvent.pos.root.y;
  5619.       event.xbutton.root=fe_event->compressedEvent.arg.button.root;
  5620.       event.xbutton.time=fe_event->compressedEvent.time;
  5621.       break;
  5622.       
  5623.     case MotionNotify:
  5624.       event.xmotion.x=fe_event->compressedEvent.pos.win.x;
  5625.       event.xmotion.y=fe_event->compressedEvent.pos.win.y;
  5626.       event.xmotion.x_root=fe_event->compressedEvent.pos.root.x;
  5627.       event.xmotion.y_root=fe_event->compressedEvent.pos.root.y;
  5628.       break;
  5629.       
  5630.     default:
  5631. #ifdef DEBUG
  5632.       fprintf(stderr,
  5633.           "fe_event_extract(): unsupported XEvent type %d\n",
  5634.           event.type);
  5635.       event.type=0;
  5636. #endif
  5637.       break;
  5638.     }
  5639.  
  5640.   if (av)
  5641.     (*av)=invertActivateKind(fe_event->activateKind);
  5642.  
  5643.   if (ac)
  5644.     {
  5645.       if (av && (*av))
  5646.     {
  5647.       static Cardinal one=1;
  5648.       (*ac)=&one;
  5649.     }
  5650.       else
  5651.     (*ac)=&zero;
  5652.     }
  5653.  
  5654.   if (mouse_action)
  5655.     (*mouse_action)=fe_event->mouse_action;
  5656.  
  5657.   return &event;
  5658. }
  5659. #endif
  5660.  
  5661. extern void plonk_cancel(void);
  5662.  
  5663. void fe_PrimarySelectionFetchURL(MWContext * context)
  5664. {
  5665.     XP_ASSERT( context != NULL );
  5666.  
  5667.     if (!context ||
  5668.         LO_HaveSelection(context) ||
  5669.         (context->type != MWContextBrowser) ||
  5670.         !CONTEXT_WIDGET(context))
  5671.     {
  5672.         return;
  5673.     }
  5674.  
  5675.     XtGetSelectionValue(CONTEXT_WIDGET(context),
  5676.                         XA_PRIMARY, 
  5677.                         XA_STRING,
  5678.                         fe_get_url_x_selection_cb,
  5679.                         (XtPointer) context,
  5680.                         CurrentTime);
  5681. }
  5682.  
  5683. static void
  5684. fe_get_url_x_selection_cb(Widget            w,
  5685.                           XtPointer            client_data,
  5686.                           Atom *            sel, 
  5687.                           Atom *            type, 
  5688.                           XtPointer            value, 
  5689.                           unsigned long *    len, 
  5690.                           int *                format)
  5691. {
  5692.     MWContext * context = (MWContext *) client_data;
  5693.     MWContext * top_context;
  5694.  
  5695.     if (!context)
  5696.     {
  5697.         return;
  5698.     }
  5699.  
  5700.     /* Load URL on the top most frame */
  5701.     top_context = XP_GetNonGridContext(context);
  5702.  
  5703.     if (!top_context)
  5704.     {
  5705.         return;
  5706.     }
  5707.  
  5708.     if (len && *len && value)
  5709.     {
  5710.         if (*type == XA_STRING)
  5711.         {
  5712.             String            str = (String) value;
  5713.             URL_Struct *    url = NET_CreateURLStruct(str,NET_DONT_RELOAD);
  5714.  
  5715.             /* hack to cancel initial sploosh-screen loader timeout */
  5716.             plonk_cancel();
  5717.  
  5718.             fe_GetURL(top_context,url,(url == NULL));
  5719.         }
  5720.     }
  5721. }
  5722.  
  5723.