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

  1. /* -*- Mode: C++; tab-width: 8; 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.    xfe.c --- other stuff specific to the X front end.
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 22-Jun-94.
  21.  */
  22.  
  23.  
  24. #include "mozilla.h"
  25. #include "altmail.h"
  26. #include "xfe.h"
  27. #include "fonts.h"
  28. #include "felocale.h"
  29. #include "intl_csi.h"
  30. #ifdef NSPR20
  31. #include "private/prpriv.h"    /* for PR_GetMonitorEntryCount */
  32. #endif /* NSPR20 */
  33.  
  34. #ifndef NSPR20
  35. #include <prevent.h>        /* for mocha */
  36. #else
  37. #include <plevent.h>        /* for mocha */
  38. #endif
  39. #include <prtypes.h>
  40. #include <libevent.h>
  41. #include <xp_list.h>
  42.  
  43. /* Layering support - LO_RefreshArea is called through compositor */
  44. #include "layers.h"
  45.  
  46. #include <X11/IntrinsicP.h>
  47. #include <X11/ShellP.h>
  48. #include <X11/Xatom.h>
  49. #ifdef DEBUG
  50. #include <X11/Xmu/Editres.h>    /* for editres to work */
  51. #endif
  52.  
  53. #include <Xfe/Xfe.h>            /* for xfe widgets and utilities */
  54.  
  55. #ifdef EDITOR
  56. #include "xeditor.h"
  57. #endif /* EDITOR */
  58. #include <Xm/Label.h>
  59.  
  60. #ifdef AIXV3
  61. #include <sys/select.h>
  62. #endif /* AIXV3 */
  63.  
  64. #include <sys/time.h>
  65.  
  66. #include <np.h>
  67.  
  68. #include "msgcom.h"
  69. #include "secnav.h"
  70. #include "mozjava.h"
  71.  
  72. #include "libmocha.h"
  73. #include "libevent.h"
  74.  
  75. #include "prefapi.h"
  76. #include "NSReg.h"
  77.  
  78. #if defined(_HPUX_SOURCE)
  79. /* I don't know where this is coming from...  "ld -y Error" says
  80.    /lib/libPW.a(xlink.o): Error is DATA UNSAT
  81.    /lib/libPW.a(xmsg.o): Error is DATA UNSAT
  82.  */
  83. int Error = 0;
  84. #endif
  85.  
  86. #include "libi18n.h"
  87.  
  88. #include "libimg.h"             /* Image Library public API. */
  89. #include "il_util.h"            /* Colormap/colorspace utilities. */
  90.  
  91. /* for XP_GetString() */
  92. #include <xpgetstr.h>
  93.  
  94. #ifndef NO_WEB_FONTS
  95. #include "nf.h"
  96. #include "Mnfrc.h"
  97. #include "Mnfrf.h"
  98. #endif
  99.  
  100. #include "XmL/GridP.h"
  101. #include "XmL/Grid.h"
  102.  
  103. extern int XFE_DOCUMENT_DONE;
  104. extern int XFE_ERROR_SAVING_OPTIONS;
  105. extern int XFE_STDERR_DIAGNOSTICS_HAVE_BEEN_TRUNCATED;
  106. extern int XFE_ERROR_CREATING_PIPE;
  107. extern int XFE_DISPLAY_FACTORY_INSTALL_COLORMAP_ERROR;
  108.  
  109. extern char *fe_calendar_path;
  110. extern char *fe_host_on_demand_path;
  111. extern char *fe_conference_path;
  112.  
  113. extern MWContext *last_documented_xref_context;
  114. extern LO_Element *last_documented_xref;
  115. extern LO_AnchorData *last_documented_anchor_data;
  116.  
  117. int fe_WindowCount = 0;
  118.  
  119. /*
  120.  * GLOBALS for new fe_find_scrollbar_sizes mechanism...
  121.  */
  122. int fe_ScrollBarW = 0;
  123. int fe_ScrollBarH = 0;
  124. Boolean fe_SBW_P = False;
  125. Boolean fe_SBH_P = False;
  126.  
  127. MWContext *someGlobalContext = NULL;
  128. static Boolean has_session_mgr= False;
  129.  
  130. #ifdef MOZ_MAIL_NEWS
  131. MSG_Master* fe_mailMaster = NULL; 
  132. MSG_Master* fe_newsMaster = NULL;
  133. #endif
  134.  
  135. struct fe_MWContext_cons *fe_all_MWContexts = 0;
  136.  
  137. void fe_delete_cb (Widget, XtPointer, XtPointer);
  138.  
  139. static void fe_save_history_timer (XtPointer closure, XtIntervalId *id);
  140. extern void fe_MakeAddressBookWidgets(Widget shell, MWContext *context);
  141.  
  142. extern void fe_ab_destroy_cb (Widget, XtPointer, XtPointer);
  143. #ifdef UNIX_LDAP
  144. extern void fe_ldapsearch_destroy_cb(Widget, XtPointer, XtPointer);
  145. #endif
  146. extern XP_Bool fe_ReadLastUserHistory(char **hist_entry_ptr);
  147.  
  148. #define DO_NOT_PASS_LAYER_N_EVENT 1
  149. #define HANDLE_LEAVE_WIN          1
  150.  
  151. #if DO_NOT_PASS_LAYER_N_EVENT
  152. extern void
  153. fe_HTMLViewTooltips(MWContext *context, 
  154.                     int x, int y, char *alt_text, 
  155.                     XFE_TipStringCallbackStruct *cb_info);
  156. #endif
  157.  
  158. /*
  159.  * Keep track of tooltip mapping to avoid conflict with fascist shells
  160.  * that insist on raising themselves - like taskbar and netcaster webtop
  161.  */
  162. static Boolean fe_tooltip_is_showing = False;
  163.  
  164. #if XmVersion >= 2000
  165. #define _XM_OBJECT_AT_POINT XmObjectAtPoint
  166. #else
  167. #define _XM_OBJECT_AT_POINT _XmInputInGadget
  168. #endif
  169.  
  170. void
  171. fe_url_exit (URL_Struct *url, int status, MWContext *context)
  172. {
  173.   XP_ASSERT (status == MK_INTERRUPTED ||
  174.              CONTEXT_DATA (context)->active_url_count > 0);
  175.  
  176.   if (CONTEXT_DATA (context)->active_url_count > 0)
  177.     CONTEXT_DATA (context)->active_url_count--;
  178.  
  179.   /* We should be guarenteed that XFE_AllConnectionsComplete() will be called
  180.      right after this, if active_url_count has just gone to 0. */
  181.   if (status < 0 && url->error_msg)
  182.     {
  183.       FE_Alert (context, url->error_msg);
  184.     }
  185. #if defined(EDITOR) && defined(EDITOR_UI)
  186.   /*
  187.    *    Do stuff specific to the editor
  188.    */
  189.   if (context->type == MWContextEditor)
  190.     fe_EditorGetUrlExitRoutine(context, url, status);
  191. #endif
  192.   if (status != MK_CHANGING_CONTEXT)
  193.     {
  194.       NET_FreeURLStruct (url);
  195.     }
  196. }
  197.  
  198. /* this func is basically XP_FindContextOfType but only returns
  199.  * a top-level non-nethelp browser context with chrome
  200.  */
  201. MWContext*
  202. fe_FindNonCustomBrowserContext(MWContext *context)
  203. {
  204.     XP_List *context_list;
  205.     int      n_context_list;
  206.     int i;
  207.  
  208.     /* If our current context has the right type, go there */
  209.     if (context && context->type == MWContextBrowser &&
  210.         !context->is_grid_cell
  211.         && !CONTEXT_DATA(context)->hasCustomChrome
  212.         && context->pHelpInfo == NULL
  213.         && !(context->name != NULL &&  /* don't use view source either */
  214.              XP_STRNCMP(context->name, "view-source", 11) == 0)) {
  215.       return context;
  216.     }
  217.  
  218.     /* otherwise, just get any other Browser context */
  219.     context_list = XP_GetGlobalContextList();
  220.     n_context_list = XP_ListCount(context_list);
  221.     for (i = 1; i <= n_context_list; i++) {
  222.         MWContext * compContext = 
  223.             (MWContext *)XP_ListGetObjectNum(context_list, i);
  224.         if (compContext->type == MWContextBrowser &&
  225.             !compContext->is_grid_cell
  226.             && !CONTEXT_DATA(compContext)->hasCustomChrome
  227.             && compContext->pHelpInfo == NULL
  228.             && !(context->name != NULL &&  /* don't use view source either */
  229.                  XP_STRNCMP(context->name, "view-source", 11) == 0)) {
  230.             /*
  231.              * NOTE:  make sure that this window is "open"...
  232.              *
  233.              */
  234.             FE_RaiseWindow(compContext);
  235.             return compContext;
  236.         }
  237.     }
  238.     return NULL;
  239. }
  240.  
  241. int
  242. FE_GetURL (MWContext *context, URL_Struct *url)
  243. {
  244.     if (!context)
  245.         return -1;
  246.  
  247.     /*
  248.      *    Rules lifted from winfe:
  249.      *
  250.      *    The only circumstance in which we load a URL
  251.      *    into Editor when called from XP code is during
  252.      *    Publishing: we have "files to post". In general, the
  253.      *    editor does not use fe_GetURL(). Editor BE has special
  254.      *    calls that deal with the special pushups an editor context
  255.      *    needs. This code delegates geturl() requests made of an editor
  256.      *    to a browser context. This will happen for help, nethelp,
  257.      *    about:, etc...djw
  258.      */
  259.     if (EDT_IS_EDITOR(context) && url->files_to_post == NULL) {
  260.         
  261.         MWContext* real_context;
  262.         
  263.         real_context = fe_FindNonCustomBrowserContext(context);
  264.         
  265.         if (!real_context) {
  266.             real_context = FE_MakeNewWindow(context, NULL, NULL, NULL);
  267.         }
  268.  
  269.         context = real_context;
  270.     }
  271.     
  272.     return fe_GetURL (context, url, FALSE);
  273. }
  274.  
  275.  
  276. extern int XFE_DesktopTypeTranslate(const char*,char**,int);
  277.  
  278. extern Boolean 
  279. xfe_NewWindowRequired(MWContext *context, const char *url)
  280. {
  281. #ifdef MOZ_MAIL_NEWS
  282.   MSG_Pane *msgPane = MSG_FindPaneOfContext(context, MSG_MESSAGEPANE);
  283.   MSG_Pane *threadPane = MSG_FindPaneOfContext(context, MSG_THREADPANE);
  284.   MSG_Pane *folderPane = MSG_FindPaneOfContext(context, MSG_FOLDERPANE);
  285. #endif
  286.   if (!context)
  287.           return True;
  288.  
  289. #ifdef MOZ_MAIL_NEWS
  290.   if (folderPane && MSG_RequiresNewsWindow(url))
  291.      return False;
  292. #endif
  293.  
  294.   return True;
  295. }
  296.  
  297. /* View the URL in the given context.
  298.    A pointer to url_string is not retained.
  299.    Returns the status of NET_GetURL().
  300.    */
  301. int
  302. fe_GetURL (MWContext *context, URL_Struct *url, Boolean skip_get_url)
  303. {
  304.   int32 x, y;
  305.   LO_Element *e;
  306.   History_entry *he;
  307.   MWContext *new_context = NULL;
  308.   char *new_address=NULL;
  309.   URL_Struct *desktop_url=NULL;
  310.   Boolean needNewWindow = False;  
  311.   /*
  312.    * See if the URL points to a local file which is a Netscape desktop
  313.    * file type. If so, extract the url from the file and create a new
  314.    * URL_Struct. (added for desktop dnd integration - Alastair.)
  315.    */
  316.  
  317.   if (XFE_DesktopTypeTranslate(url->address,&new_address,TRUE)) {
  318.       if (new_address && XP_STRLEN(new_address)>0) {
  319.           desktop_url=NET_CreateURLStruct (new_address,NET_DONT_RELOAD);
  320.           if (desktop_url) {
  321.               NET_FreeURLStruct(url);
  322.               url=desktop_url;
  323.           }
  324.       }
  325.   }
  326.   
  327. #ifdef JAVA
  328.   /*
  329.   ** This hack is to get around the crash when we have an
  330.   ** auto-config proxy installed, and we come up in the mail
  331.   ** window and get a message with an applet on it:
  332.   */
  333.   if (context->type == MWContextJava) {
  334.       context = NSN_JavaContextToRealContext(context);
  335.   }
  336. #endif
  337.  
  338. #ifdef MOZ_MAIL_NEWS
  339.   /* If this URL requires a particular kind of window, and this is not
  340.      that kind of window, then we need to find or create one.
  341.    */
  342.   if (!skip_get_url && 
  343. #ifdef EDITOR
  344.       !(context->is_editor) &&
  345. #endif
  346.       (needNewWindow = MSG_NewWindowRequired(context, url->address)) &&
  347.       XP_STRCMP(url->address, "search-libmsg:"))
  348.     {
  349.  
  350.       XP_ASSERT (!MSG_NewWindowProhibited (context, url->address));
  351.      
  352.       if ( context->type != MWContextSearch
  353.            && context->type != MWContextSearchLdap
  354.            /* Skip for Nethelp which  will create its
  355.             * own new window if it is needed */
  356.            && NET_URL_Type(url->address) != NETHELP_TYPE_URL )
  357.  
  358.     {
  359.  
  360.       if ( MSG_RequiresBrowserWindow(url->address) )
  361.         {
  362.         new_context = fe_FindNonCustomBrowserContext(context);
  363.         }
  364.  
  365.       if ( new_context )
  366.         {
  367.             /* If we find a new browser context, use it to display URL 
  368.              */
  369.             if (context != new_context) {
  370.                 /* If we have picked an existing context that isn't this
  371.                  * one in which to display this document, make sure that
  372.                  * context is uniconified and raised first. 
  373.                  */
  374.  
  375.                 /* Popup the shell first, so that we gurantee its realized 
  376.                  */
  377.                 XtPopup(CONTEXT_WIDGET(new_context),XtGrabNone);
  378.  
  379.                 /* Force the window to the front and de-iconify if needed 
  380.                  */
  381.                 XMapRaised(XtDisplay(CONTEXT_WIDGET(new_context)),
  382.                            XtWindow(CONTEXT_WIDGET(new_context)));
  383.             }
  384.             context = new_context;
  385.         }
  386.     }
  387.     }
  388. #endif /* MOZ_MAIL_NEWS */
  389.  
  390.   e = LO_XYToNearestElement (context,
  391.                  CONTEXT_DATA (context)->document_x,
  392.                  CONTEXT_DATA (context)->document_y,
  393.                              NULL);
  394.  
  395.   he = SHIST_GetCurrent (&context->hist);
  396.  
  397.   if (e)
  398.     SHIST_SetPositionOfCurrentDoc (&context->hist, e->lo_any.ele_id);
  399.  
  400.   /* LOU: don't do this any more since Layout will do it
  401.    * for you once the page starts loading
  402.    *
  403.    * Here is why we have to do this for now...
  404.    * 
  405.    * | This is important feedback on this new "feature" (or misfeature as
  406.    * | it may turn out).
  407.    * 
  408.    * If this is the feature where the front end no longer calls
  409.    * XP_InterruptContext() inside fe_GetURL(), but only when data from
  410.    * the new URL arrives, then I think I understand what's going on.
  411.    * 
  412.    * | I didn't expect the images that are currently transfering to interfere
  413.    * | significantly with the TCP connection setup,
  414.    * 
  415.    * They won't interfere within TCP or IP modules on intervening routers.
  416.    * ISDN signalling guarantees perfect scheduling of the D-channel; modem
  417.    * link layers are fair.
  418.    * 
  419.    * The problem is this: before, when fe_GetURL() called XP_InterruptContext(),
  420.    * the connections for the old document were closed immediately.  Those TCP
  421.    * closes turned into packets with the FIN flag set on the wire, which went to
  422.    * the server over the fairly-scheduled link.  The client moved into TCP state
  423.    * FIN_WAIT_1, indicating that it had sent a FIN but needed an ACK, and that
  424.    * the server had not yet closed its half of the connection.  As soon as the
  425.    * next TCP segment for this connection arrived at the client, the client TCP
  426.    * noticed that the user process had closed, so it aborted the connection by
  427.    * sending a RST.
  428.    * 
  429.    * Since the change to the front ends, it appears the old connections don't
  430.    * (all) get closed until data on the new connection arrives.  The data for
  431.    * those old connections that are not yet closed will still be queued in the
  432.    * server's TCP, and sent as the client ACKs previous data and updates the
  433.    * server's window.  There is no way for an HTTP daemon to cancel the write
  434.    * or send syscalls that enqueued this data, once the syscall has returned.
  435.    * Only a RST from the client for each old connection will cause the server
  436.    * to kill its enqueued data.
  437.    * 
  438.    * I doubt there is much data in the fairly narrow pipe between server and
  439.    * client.  Because the pipe is narrow, the server TCP has not opened its
  440.    * congestion window, and there cannot be much data in flight.  The problem
  441.    * is lack of abort because of lack of close() when the new URL is clicked.
  442.    * 
  443.    * | Perhaps there is some TCP magic that we can do
  444.    * | to cause the new stream to have absolute priority over other TCP
  445.    * | streams.
  446.    * 
  447.    * No such magic, nor any need for it in this scenario.
  448.    * 
  449.    * | I could also pause all the transfering connections while
  450.    * | we are waiting.
  451.    * 
  452.    * Only a close, which guarantees an abort when more old data arrives, will
  453.    * do the trick.  Anything else requires server mods as well as client.
  454.    */
  455.   if (!skip_get_url &&
  456.       XP_STRNCMP("view-source:", url->address, 12) != 0) {
  457.     XP_InterruptContext (context); 
  458.   }
  459.  
  460.   if (CONTEXT_DATA (context)->refresh_url_timer)
  461.     {
  462.       XtRemoveTimeOut (CONTEXT_DATA (context)->refresh_url_timer);
  463.       CONTEXT_DATA (context)->refresh_url_timer = 0;
  464.     }
  465.   if (CONTEXT_DATA (context)->refresh_url_timer_url)
  466.     {
  467.       free (CONTEXT_DATA (context)->refresh_url_timer_url);
  468.       CONTEXT_DATA (context)->refresh_url_timer_url = 0;
  469.     }
  470.  
  471.   if (url && XP_FindNamedAnchor (context, url, &x, &y))
  472.     {
  473.       char *temp;
  474.       URL_Struct *urlcp;
  475.       
  476.       fe_ScrollTo (context, 0, y);
  477.  
  478.       if (! CONTEXT_DATA (context)->is_resizing) {
  479.         fe_SetURLString (context, url);
  480.       }
  481.  
  482.       /* Create URL from prev history entry to preserve security, etc. */
  483.       urlcp = SHIST_CreateURLStructFromHistoryEntry(context, he);
  484.  
  485.       /*  Swap addresses. */
  486.       temp = url->address;
  487.       url->address = urlcp->address;
  488.       urlcp->address = temp;
  489.     
  490.       /* set history_num correctly */
  491.       urlcp->history_num = url->history_num;
  492.       
  493.       /*  Free old URL, and reassign. */
  494.       NET_FreeURLStruct(url);
  495.       url = urlcp;
  496.       NET_FreeURLStruct (url);
  497.       fe_RefreshAllAnchors ();
  498.       return 0;
  499.     }
  500.   else
  501.     {
  502. #ifdef EDITOR
  503.       /*
  504.        *    We have to pass "about:" docs through the old way,
  505.        *    cause there's all this magic that happens! We do trap
  506.        *    these in fe_EditorNew() so the user will not be allowed
  507.        *    to edit them, but *we* do GetURLs on them as well.
  508.        */
  509.       if (EDT_IS_EDITOR(context) && strncasecmp(url->address, "about:", 6)!= 0)
  510.       return fe_GetSecondaryURL (context, url, FO_EDIT, 0,
  511.                         skip_get_url);
  512.       else
  513. #endif
  514.       return fe_GetSecondaryURL (context, url, FO_CACHE_AND_PRESENT, 0,
  515.                     skip_get_url);
  516.     }
  517. }
  518.  
  519.  
  520. /* Start loading a URL other than the main one (ie, an embedded image.)
  521.    A pointer to url_string is not retained.
  522.    Returns the status of NET_GetURL().
  523.  */
  524. int
  525. fe_GetSecondaryURL (MWContext *context,
  526.             URL_Struct *url_struct,
  527.             int output_format,
  528.             void *call_data, Boolean skip_get_url)
  529. {
  530.   /* The URL will be freed when libnet calls the fe_url_exit() callback. */
  531.  
  532.   /* If the URL_Struct already has fe_data, try to preserve it.  (HTTP publishing in the 
  533.      editor, EDT_PublishFileTo(), uses it.) */
  534.   if (call_data) {
  535.     XP_ASSERT(!url_struct->fe_data);
  536.     url_struct->fe_data = call_data;
  537.   }
  538.   /* else leave url_struct->fe_data alone */
  539.  
  540.  
  541.   CONTEXT_DATA (context)->active_url_count++;
  542.   if (CONTEXT_DATA (context)->active_url_count == 1)
  543.     {
  544.       CONTEXT_DATA (context)->clicking_blocked = True;
  545.  
  546.       if (context->is_grid_cell)
  547.         {
  548.           MWContext *top_context = context;
  549.           while ((top_context->grid_parent)&&
  550.         (top_context->grid_parent->is_grid_cell))
  551.             {
  552.           top_context = top_context->grid_parent;
  553.             }
  554.           fe_StartProgressGraph (top_context->grid_parent);
  555.         }
  556.       else
  557.         {
  558.       fe_StartProgressGraph (context);
  559.         }
  560.  
  561.       fe_SetCursor (context, False);
  562.  
  563.       /* Enable stop here (uses active_url_count) 
  564.        * This makes the stop button active during
  565.        * host lookup and initial connection.
  566.        */
  567.       FE_UpdateStopState(context);
  568.     }
  569.  
  570.   if (skip_get_url)
  571.     {
  572.       return(0);
  573.     }
  574.  
  575.   return NET_GetURL (url_struct, output_format, context, fe_url_exit);
  576. }
  577.  
  578. static XtInputId fe_fds_to_XtInputIds [FD_SETSIZE] = { 0, };
  579.  
  580. static void
  581. fe_stream_callback (void *closure, int *source, XtInputId *id)
  582. {
  583. #ifdef QUANTIFY
  584. quantify_start_recording_data();
  585. #endif /* QUANTIFY */
  586.  
  587. #ifdef NSPR20_DISABLED
  588.   NET_ProcessNet (*source, NET_UNKNOWN_FD);
  589. #endif
  590.  
  591. #ifdef QUANTIFY
  592. quantify_stop_recording_data();
  593. #endif /* QUANTIFY */
  594. }
  595.  
  596. static void
  597. fe_add_input (int fd, int mask)
  598. {
  599.   if (fd < 0 || fd >= countof (fe_fds_to_XtInputIds))
  600.     abort ();
  601.  
  602.   LOCK_FDSET();
  603.   
  604. #ifdef UNIX_ASYNC_DNS
  605.   if (fe_UseAsyncDNS() && fe_fds_to_XtInputIds [fd]) {
  606.       /* If we're already selecting input on this fd, don't select it again
  607.          and lose our pointer to the XtInput object..  This shouldn't happen,
  608.          but netlib does this when async DNS lookups are happening.  (This
  609.          will lose if the `mask' arg has changed on two consecutive calls
  610.          without an intervening call to `fe_remove_input', but that doesn't
  611.          happen.)  -- jwz, 9-Jan-97.
  612.          */
  613.       goto DONE;
  614.   }
  615. #endif
  616.  
  617.   fe_fds_to_XtInputIds [fd] = XtAppAddInput (fe_XtAppContext, fd,
  618.                          (XtPointer) mask,
  619.                          fe_stream_callback, 0);
  620. #ifdef JAVA
  621.   if (PR_CurrentThread() != mozilla_thread) {
  622.       /*
  623.       ** Sometimes a non-mozilla thread will be using the netlib to fetch
  624.       ** data. Because mozilla is the only thread that runs the netlib
  625.       ** "select" code, we need to be able to kick mozilla and wake it up
  626.       ** when the select set has changed.
  627.       **
  628.       ** A way to do this would be to have mozilla stop calling select
  629.       ** and instead manually manipulate the idle' thread's select set,
  630.       ** but there is yet to be an NSPR interface at that level.
  631.       */
  632.       PR_PostEvent(mozilla_event_queue, NULL);
  633.   }
  634. #endif /* JAVA */
  635.  
  636. #ifdef UNIX_ASYNC_DNS
  637. DONE:
  638. #endif
  639.   UNLOCK_FDSET();
  640. }
  641.  
  642. static void
  643. fe_remove_input (int fd)
  644. {
  645.   if (fd < 0 || fd >= countof (fe_fds_to_XtInputIds))
  646.     return;    /* was abort() --  */
  647.  
  648.   LOCK_FDSET();
  649.  
  650.   if (fe_fds_to_XtInputIds [fd] != 0) {
  651.       XtRemoveInput (fe_fds_to_XtInputIds [fd]);
  652.       fe_fds_to_XtInputIds [fd] = 0;
  653.   }
  654.  
  655.   UNLOCK_FDSET();
  656. }
  657.  
  658. void
  659. FE_SetReadSelect (MWContext *context, int fd)
  660. {
  661.   fe_add_input (fd, XtInputReadMask | XtInputExceptMask);
  662. }
  663.  
  664. void
  665. FE_SetConnectSelect (MWContext *context, int fd)
  666. {
  667.   fe_add_input (fd, (XtInputWriteMask | XtInputExceptMask));
  668. }
  669.  
  670. void
  671. FE_ClearReadSelect (MWContext *context, int fd)
  672. {
  673.   fe_remove_input (fd);
  674. }
  675.  
  676. void
  677. FE_ClearConnectSelect (MWContext *context, int fd)
  678. {
  679.   FE_ClearReadSelect (context, fd);
  680. }
  681.  
  682. void
  683. FE_ClearFileReadSelect (MWContext *context, int fd)
  684. {
  685.   FE_ClearReadSelect (context, fd);
  686. }
  687.  
  688. void
  689. FE_SetFileReadSelect (MWContext *context, int fd)
  690. {
  691.   FE_SetReadSelect (context, fd);
  692. }
  693.  
  694.  
  695. /* making contexts and windows */
  696.  
  697. static unsigned int
  698. default_char_width (int charset, fe_Font font)
  699. {
  700.   XCharStruct overall;
  701.   int ascent, descent;
  702.   FE_TEXT_EXTENTS(charset, font, "n", 1, &ascent, &descent, &overall);
  703.   return overall.width;
  704. }
  705.  
  706.  
  707. static void fe_pick_visual_and_colormap (Widget toplevel,
  708.                      MWContext *new_context);
  709. void fe_get_context_resources (MWContext *context);
  710. void fe_get_final_context_resources (MWContext *context);
  711.  
  712. MWContext *
  713. fe_MakeWindow(Widget toplevel, MWContext *context_to_copy,
  714.             URL_Struct *url, char *window_name, MWContextType type,
  715.             Boolean skip_get_url)
  716. {
  717.     return fe_MakeNewWindow(toplevel, context_to_copy, url, window_name, type,
  718.                 skip_get_url, NULL);
  719. }
  720.  
  721. static void
  722. fe_position_download_context(MWContext *context)
  723. {
  724.   MWContext *active_context = NULL;
  725.   Widget shell = CONTEXT_WIDGET(context);
  726.  
  727.   XP_ASSERT(context->type == MWContextSaveToDisk);
  728.  
  729.   /* Lets position this ourselves. If window manager interactive placement
  730.      is on and this context doesn't exist for more than a few microsecs,
  731.      then the user would see this as a outline, place it somewhere but
  732.      wouldn't see a window at all.
  733.   */
  734.   if (fe_all_MWContexts->next)
  735.     active_context = fe_all_MWContexts->next->context;
  736.   if (active_context) {
  737.     WMShellWidget wmshell = (WMShellWidget) shell;
  738.     Widget parent = CONTEXT_WIDGET(active_context);
  739.     Screen* screen = XtScreen (parent);
  740.     Dimension screen_width = WidthOfScreen (screen);
  741.     Dimension screen_height = HeightOfScreen (screen);
  742.     Dimension parent_width = 0;
  743.     Dimension parent_height = 0;
  744.     Dimension child_width = 0;
  745.     Dimension child_height = 0;
  746.     Position x;
  747.     Position y;
  748.     XSizeHints size_hints;
  749.  
  750.     XtRealizeWidget (shell);  /* to cause its size to be computed */
  751.  
  752.     XtVaGetValues(shell,
  753.               XtNwidth, &child_width, XtNheight, &child_height, 0);
  754.     XtVaGetValues (parent,
  755.                XtNwidth, &parent_width, XtNheight, &parent_height, 0);
  756.  
  757.     x = (((Position)parent_width) - ((Position)child_width)) / 2;
  758.     y = (((Position)parent_height) - ((Position)child_height)) / 2;
  759.     XtTranslateCoords (parent, x, y, &x, &y);
  760.  
  761.     if ((Dimension) (x + child_width) > screen_width)
  762.       x = screen_width - child_width;
  763.     if (x < 0)
  764.       x = 0;
  765.  
  766.     if ((Dimension) (y + child_height) > screen_height)
  767.       y = screen_height - child_height;
  768.     if (y < 0)
  769.       y = 0;
  770.  
  771.     XtVaSetValues (shell, XtNx, x, XtNy, y, 0);
  772.  
  773.     /* Horrific kludge */
  774.     wmshell->wm.size_hints.flags &= (~PPosition);
  775.     wmshell->wm.size_hints.flags |= USPosition;
  776.     if (XGetNormalHints (XtDisplay(shell), XtWindow(shell), &size_hints)) {
  777.       size_hints.x = wmshell->wm.size_hints.x;
  778.       size_hints.y = wmshell->wm.size_hints.y;
  779.       size_hints.flags &= (~PPosition);
  780.       size_hints.flags |= USPosition;
  781.       XSetNormalHints (XtDisplay(shell), XtWindow(shell), &size_hints);
  782.     }
  783.   }
  784. }
  785.  
  786. void
  787. fe_find_scrollbar_sizes(MWContext *context)
  788. {
  789.     /* Figure out how much space the horizontal & vertical scrollbars take up.
  790.      * It's basically impossible to determine this before creating them...
  791.      */
  792.     if (CONTEXT_DATA(context)->scrolled) {
  793.         Boolean   hscrollP = XtIsManaged(CONTEXT_DATA (context)->hscroll);
  794.         Boolean   vscrollP = XtIsManaged(CONTEXT_DATA (context)->vscroll);
  795.         Dimension w1 = 0, w2 = 0;
  796.         Dimension h1 = 0, h2 = 0;
  797.         
  798.         XtVaGetValues (CONTEXT_DATA (context)->drawing_area, 
  799.                        XmNwidth, &w2, 
  800.                        XmNheight, &h2, 
  801.                        0);
  802.  
  803.         /* Vertical ScrollBar dimensions...
  804.          * 
  805.          */
  806.         if (!fe_SBW_P) {
  807.             XtVaGetValues (CONTEXT_DATA (context)->scrolled, 
  808.                            XmNwidth, &w1, 0);
  809.             if (vscrollP) {
  810.                 fe_ScrollBarW = w1 - w2;
  811.                 fe_SBW_P = True;
  812.             }
  813.             else {
  814.                 /*
  815.                  * MAGIC Number... [ default value ]
  816.                  */
  817.                 fe_ScrollBarW = 15;
  818.             }
  819.         }
  820.         CONTEXT_DATA (context)->sb_w = fe_ScrollBarW;
  821.         CONTEXT_DATA (context)->scrolled_width = (unsigned long) w2;
  822.  
  823.         /* Horizontal ScrollBar dimensions...
  824.          * 
  825.          */
  826.         if (!fe_SBH_P) {
  827.             if (hscrollP) {
  828.                 XtVaGetValues (CONTEXT_DATA (context)->scrolled, 
  829.                                XmNheight, &h1, 0);
  830.                 fe_ScrollBarH = h1 - h2;
  831.                 fe_SBH_P = True;
  832.             }
  833.             else {
  834.                 /*
  835.                  * MAGIC Number... [ default value ]
  836.                  */
  837.                 fe_ScrollBarH = 15;
  838.                 }
  839.         }
  840.         CONTEXT_DATA (context)->sb_h = fe_ScrollBarH;
  841.         CONTEXT_DATA (context)->scrolled_height = (unsigned long) h2;
  842.     }
  843. }
  844.  
  845.  
  846. void
  847. fe_load_default_font(MWContext *context)
  848. {
  849.   fe_Font font;
  850.   int ascent;
  851.   int descent;
  852.   int16 charset;
  853.  
  854.   charset = CS_LATIN1;
  855.   font = fe_LoadFontFromFace(context, NULL, &charset, 0, 3, 0);
  856.   if (!font)
  857.   {
  858.     CONTEXT_DATA (context)->line_height = 17;
  859.     return;
  860.   }
  861.   FE_FONT_EXTENTS(CS_LATIN1, font, &ascent, &descent);
  862.   CONTEXT_DATA (context)->line_height = ascent + descent;
  863.   fe_DoneWithFont(font);
  864. }
  865.  
  866. static void
  867. fe_focus_notify_eh (Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
  868. {
  869.   MWContext *context = (MWContext *) closure;
  870.   JSEvent *event;
  871.  
  872.   TRACEMSG (("fe_focus_notify_eh\n"));
  873.   switch (ev->type) {
  874.   case FocusIn:
  875.     TRACEMSG (("focus in\n"));
  876.     fe_MochaFocusNotify(context, NULL);
  877.     break;
  878.   case FocusOut:
  879.     TRACEMSG (("focus out\n"));
  880.     fe_MochaBlurNotify(context, NULL);
  881.     break;
  882.   }
  883. }
  884.  
  885. void
  886. fe_map_notify_eh (Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
  887. {
  888. #ifdef JAVA
  889.     MWContext *context = (MWContext *) closure;
  890.     switch (ev->type) {
  891.     case MapNotify:
  892.     LJ_UniconifyApplets(context);
  893.     break;
  894.     case UnmapNotify:
  895.     LJ_IconifyApplets(context);
  896.     break;
  897.     }
  898. #endif /* JAVA */
  899. }
  900.  
  901. void
  902. fe_copy_context_settings(MWContext *to, MWContext *from)
  903. {
  904.   /* notyet fe_ContextData* dto; */
  905.  
  906.   if ((NULL==to) || (NULL==from))
  907.     return;
  908.  
  909.   /* set default doc_csid */
  910.   if ((NULL!=to->fe.data) && (NULL!=from->fe.data)) {
  911.       to->fe.data->xfe_doc_csid = from->fe.data->xfe_doc_csid;
  912.   }
  913.  
  914. #ifdef notyet
  915.   dto = CONTEXT_DATA(to);
  916.   if (from) {
  917.     fe_ContextData* dfrom = CONTEXT_DATA(from);
  918.     dto->show_url_p        = dfrom->show_url_p;
  919.     dto->show_toolbar_p        = dfrom->show_toolbar_p;
  920.     dto->show_toolbar_icons_p    = dfrom->show_toolbar_icons_p;
  921.     dto->show_toolbar_text_p    = dfrom->show_toolbar_text_p;
  922. #ifdef EDITOR
  923.     dto->show_character_toolbar_p = dfrom->show_character_toolbar_p;
  924.     dto->show_paragraph_toolbar_p = dfrom->show_paragraph_toolbar_p;
  925. #endif
  926.     dto->show_directory_buttons_p = dfrom->show_directory_buttons_p;
  927.     dto->show_menubar_p           = dfrom->show_menubar_p;
  928.     dto->show_bottom_status_bar_p = dfrom->show_bottom_status_bar_p;
  929. #ifndef NO_SECURITY
  930.     dto->show_security_bar_p    = dfrom->show_security_bar_p;
  931. #endif
  932.     dto->autoload_images_p    = dfrom->autoload_images_p;
  933.     dto->loading_images_p    = False;
  934.     dto->looping_images_p    = False;
  935.     dto->delayed_images_p    = dfrom->delayed_images_p;
  936.     dto->force_load_images    = 0;
  937.     dto->fancy_ftp_p        = dfrom->fancy_ftp_p;
  938.     dto->xfe_doc_csid        = dfrom->xfe_doc_csid;
  939.     dto->XpixelsPerPoint        = dfrom->XpixelsPerPoint;
  940.     dto->YpixelsPerPoint        = dfrom->YpixelsPerPoint;
  941.   }
  942.   else {
  943.     dto->show_url_p        = fe_globalPrefs.show_url_p;
  944.     dto->show_toolbar_p        = fe_globalPrefs.show_toolbar_p;
  945. #ifdef EDITOR
  946.     dto->show_character_toolbar_p = fe_globalPrefs.editor_character_toolbar;
  947.     dto->show_paragraph_toolbar_p = fe_globalPrefs.editor_paragraph_toolbar;
  948. #endif
  949.     dto->show_toolbar_icons_p    = fe_globalPrefs.toolbar_icons_p;
  950.     dto->show_toolbar_text_p    = fe_globalPrefs.toolbar_text_p;
  951.     dto->show_directory_buttons_p = fe_globalPrefs.show_directory_buttons_p;
  952.     dto->show_menubar_p           = fe_globalPrefs.show_menubar_p;
  953.     dto->show_bottom_status_bar_p = fe_globalPrefs.show_bottom_status_bar_p;
  954. #ifndef NO_SECURITY
  955.     dto->show_security_bar_p    = fe_globalPrefs.show_security_bar_p;
  956. #endif
  957.     dto->autoload_images_p    = fe_globalPrefs.autoload_images_p;
  958.     dto->loading_images_p    = False;
  959.     dto->looping_images_p    = False;
  960.     dto->delayed_images_p    = False;
  961.     dto->force_load_images    = 0;
  962.     dto->fancy_ftp_p        = fe_globalPrefs.fancy_ftp_p;
  963.     dto->xfe_doc_csid        = INTL_DefaultDocCharSetID(NULL);
  964.     /* XpixelsPerPoint and YpixelsPerPoint are caculated in 
  965.      * XFE_Frame::initializeMWContext.
  966.      */
  967.   }
  968. #endif /* notyet */
  969.  
  970. }
  971.  
  972. /* #### mailnews.c */
  973. extern void fe_set_compose_wrap_state(MWContext *context, XP_Bool wrap_p);
  974.  
  975. /* XXX - "temporary" routine until we pass fe_drawable's straight from
  976.    layout to FE drawing functions */
  977. void
  978. XFE_SetDrawable(MWContext *context, CL_Drawable *drawable)
  979.   fe_Drawable *fe_drawable;
  980.   if (! drawable)
  981.     return;
  982.  
  983.   fe_drawable = (fe_Drawable*)CL_GetDrawableClientData(drawable);
  984.   CONTEXT_DATA(context)->drawable = fe_drawable;
  985. }
  986.  
  987. /* Callback to set the XY offset for all drawing into this drawable */
  988. static void
  989. fe_set_drawable_origin(CL_Drawable *drawable, int32 x_origin, int32 y_origin) 
  990. {
  991.   fe_Drawable *fe_drawable = 
  992.     (fe_Drawable*)CL_GetDrawableClientData(drawable);
  993.   fe_drawable->x_origin = x_origin;
  994.   fe_drawable->y_origin = y_origin;
  995. }
  996.  
  997. /* Callback to set the clip region for all drawing calls */
  998. static void
  999. fe_set_drawable_clip(CL_Drawable *drawable, FE_Region clip_region)
  1000. {
  1001.   fe_Drawable *fe_drawable = 
  1002.     (fe_Drawable*)CL_GetDrawableClientData(drawable);
  1003.   fe_drawable->clip_region = clip_region;
  1004. }
  1005.  
  1006. /* Callback not necessary, but may help to locate errors */
  1007. static void
  1008. fe_restore_drawable_clip(CL_Drawable *drawable)
  1009. {
  1010.   fe_Drawable *fe_drawable = 
  1011.     (fe_Drawable*)CL_GetDrawableClientData(drawable);
  1012.   fe_drawable->clip_region = NULL;
  1013. }
  1014.  
  1015. /* XXX - Works faster if we don't define this, but seems to introduce bugs */
  1016. #define USE_REGION_FOR_COPY
  1017.  
  1018. #ifndef USE_REGION_FOR_COPY
  1019.  
  1020. static Drawable fe_copy_src, fe_copy_dst;
  1021. static GC fe_copy_gc;
  1022.  
  1023. static void
  1024. fe_copy_rect_func(void *empty, XP_Rect *rect)
  1025. {
  1026.   XCopyArea (fe_display, fe_copy_src, fe_copy_dst, fe_copy_gc,
  1027.          rect->left, rect->top,
  1028.          rect->right - rect->left, rect->bottom - rect->top,
  1029.          rect->left, rect->top);
  1030. }
  1031. #endif
  1032.  
  1033. static void
  1034. fe_copy_pixels(CL_Drawable *drawable_src, 
  1035.                CL_Drawable *drawable_dst, 
  1036.                FE_Region region)
  1037. {
  1038.   XP_Rect bbox;
  1039.   XGCValues gcv;
  1040.   GC gc;
  1041.   fe_Drawable *fe_drawable_dst = 
  1042.     (fe_Drawable*)CL_GetDrawableClientData(drawable_dst);
  1043.   fe_Drawable *fe_drawable_src = 
  1044.     (fe_Drawable*)CL_GetDrawableClientData(drawable_src);
  1045.  
  1046.   Drawable src = fe_drawable_src->xdrawable;
  1047.   Drawable dst = fe_drawable_dst->xdrawable;
  1048.  
  1049.   /* FIXME - for simple regions, it may be faster to iterate over
  1050.      rectangles rather than using clipping regions */ 
  1051.   memset (&gcv, ~0, sizeof (gcv));
  1052.   gcv.function = GXcopy;
  1053.  
  1054. #ifdef USE_REGION_FOR_COPY
  1055.   gc = fe_GetGCfromDW (fe_display, dst, GCFunction, &gcv, region);
  1056.  
  1057.   FE_GetRegionBoundingBox(region, &bbox);
  1058.   XCopyArea (fe_display, src, dst, gc, bbox.left, bbox.top,
  1059.          bbox.right - bbox.left, bbox.bottom - bbox.top,
  1060.          bbox.left, bbox.top);
  1061. #else
  1062.   fe_copy_gc = fe_GetGCfromDW (fe_display, dst, GCFunction, &gcv, NULL);
  1063.   fe_copy_src = src;
  1064.   fe_copy_dst = dst;
  1065.   FE_ForEachRectInRegion(region, 
  1066.              (FE_RectInRegionFunc)fe_copy_rect_func, NULL);
  1067. #endif
  1068. }
  1069.  
  1070. /* There is only one backing store pixmap shared among all windows */
  1071. static Pixmap fe_backing_store_pixmap = 0;
  1072.  
  1073. /* We use a serial number to compare pixmaps rather than the X Pixmap
  1074.    handle itself, in case the server allocates a pixmap with the same
  1075.    handle as a pixmap that we've deallocated.  */
  1076. static int fe_backing_store_pixmap_serial_num = 0;
  1077.  
  1078. /* Current lock owner for backing store */
  1079. static fe_Drawable *backing_store_owner = NULL;
  1080. static int backing_store_width = 0;
  1081. static int backing_store_height = 0;
  1082. static int backing_store_refcount = 0;
  1083. static int backing_store_depth;
  1084.  
  1085. static void
  1086. fe_destroy_backing_store(CL_Drawable *drawable)
  1087. {
  1088.   XFreePixmap(fe_display, fe_backing_store_pixmap);
  1089.   backing_store_owner = NULL;
  1090.   fe_backing_store_pixmap = 0;
  1091.   backing_store_width = 0;
  1092.   backing_store_height = 0;
  1093. }
  1094.  
  1095. /* Function that's called to indicate that the drawable will be used.
  1096.    No other drawable calls will be made until we InitDrawable. */
  1097. static void
  1098. fe_init_drawable(CL_Drawable *drawable)
  1099. {
  1100.   backing_store_refcount++;
  1101. }
  1102.   
  1103. /* Function that's called to indicate that we're temporarily done with
  1104.    the drawable. The drawable won't be used until we call InitDrawable
  1105.    again. */
  1106. static void
  1107. fe_relinquish_drawable(CL_Drawable *drawable)
  1108. {
  1109.   XP_ASSERT(backing_store_refcount > 0);
  1110.   backing_store_refcount--;
  1111.  
  1112.   if (backing_store_refcount == 0)
  1113.     fe_destroy_backing_store(drawable);
  1114. }
  1115.  
  1116. static PRBool
  1117. fe_lock_drawable(CL_Drawable *drawable, CL_DrawableState new_state)
  1118. {
  1119.   fe_Drawable *prior_backing_store_owner;
  1120.   fe_Drawable *fe_drawable = (fe_Drawable *)CL_GetDrawableClientData(drawable);
  1121.   if (new_state == CL_UNLOCK_DRAWABLE)
  1122.     return PR_TRUE;
  1123.     
  1124.   XP_ASSERT(backing_store_refcount > 0);
  1125.  
  1126.   if (!fe_backing_store_pixmap)
  1127.       return PR_FALSE;
  1128.  
  1129.   prior_backing_store_owner = backing_store_owner;
  1130.  
  1131.   /* Check to see if we're the last one to use this drawable.
  1132.      If not, someone else might have modified the bits, since the
  1133.      last time we wrote to them using this drawable. */
  1134.   if (new_state & CL_LOCK_DRAWABLE_FOR_READ) {
  1135.     if (prior_backing_store_owner != fe_drawable)
  1136.         return PR_FALSE;
  1137.  
  1138.     /* The pixmap could have changed since the last time this
  1139.        drawable was used due to a resize of the backing store, even
  1140.        though no one else has drawn to it.  */
  1141.     if (fe_drawable->xdrawable_serial_num !=
  1142.         fe_backing_store_pixmap_serial_num) {
  1143.         return PR_FALSE;
  1144.     }
  1145.   }
  1146.  
  1147.   backing_store_owner = fe_drawable;
  1148.  
  1149.   fe_drawable->xdrawable = fe_backing_store_pixmap;
  1150.   fe_drawable->xdrawable_serial_num = fe_backing_store_pixmap_serial_num;
  1151.  
  1152.   return PR_TRUE;
  1153. }
  1154.  
  1155. static void
  1156. fe_set_drawable_dimensions(CL_Drawable *drawable, uint32 width, uint32 height)
  1157. {
  1158.   Window backing_store_window;
  1159.   struct fe_MWContext_cons *cntx;
  1160.   fe_Drawable *fe_drawable = 
  1161.     (fe_Drawable*)CL_GetDrawableClientData(drawable);
  1162.  
  1163.   XP_ASSERT(backing_store_refcount > 0);
  1164.   if ((width > backing_store_width) || (height > backing_store_height)) {  
  1165.         
  1166.     /* The backing store only gets larger, not smaller. */
  1167.     if (width < backing_store_width)
  1168.       width = backing_store_width;
  1169.     if (height < backing_store_height)
  1170.       height = backing_store_height;
  1171.         
  1172.     if (fe_backing_store_pixmap) {
  1173.       XFreePixmap(fe_display, fe_backing_store_pixmap);
  1174.       backing_store_owner = NULL;
  1175.     }
  1176.  
  1177.     fe_backing_store_pixmap_serial_num++;
  1178.  
  1179.     /* Grab a window for use with XCreatePixmap.  X doesn't care about
  1180.        what window we use, as long as it's on the same screen that the
  1181.        pixmap will be drawn on. */
  1182.     backing_store_window = 0;
  1183.     for (cntx = fe_all_MWContexts; cntx; cntx = cntx->next) {
  1184.         if (CONTEXT_DATA (cntx->context)->drawing_area != NULL) {
  1185.             backing_store_window = 
  1186.                 XtWindow (CONTEXT_DATA (cntx->context)->drawing_area);
  1187.             if (backing_store_window)
  1188.                 break;
  1189.         }
  1190.     }
  1191.     if (!backing_store_window) {
  1192.         XP_ASSERT(0);
  1193.         return;
  1194.     }
  1195.  
  1196.     fe_backing_store_pixmap = XCreatePixmap (fe_display, 
  1197.                          backing_store_window,
  1198.                          width, height,
  1199.                          backing_store_depth);
  1200.     backing_store_width = width;
  1201.     backing_store_height = height;
  1202.   }
  1203.   fe_drawable->xdrawable = fe_backing_store_pixmap;
  1204. }
  1205.  
  1206. static
  1207. CL_DrawableVTable window_drawable_vtable = {
  1208.     NULL,
  1209.     NULL,
  1210.     NULL,
  1211.     NULL,
  1212.     fe_set_drawable_origin,
  1213.     NULL,
  1214.     fe_set_drawable_clip,
  1215.     fe_restore_drawable_clip,
  1216.     fe_copy_pixels,
  1217.     NULL
  1218. };
  1219.  
  1220. static
  1221. CL_DrawableVTable backing_store_drawable_vtable = {
  1222.     fe_lock_drawable,
  1223.     fe_init_drawable,
  1224.     fe_relinquish_drawable,
  1225.     NULL,
  1226.     fe_set_drawable_origin,
  1227.     NULL,
  1228.     fe_set_drawable_clip,
  1229.     fe_restore_drawable_clip,
  1230.     fe_copy_pixels,
  1231.     fe_set_drawable_dimensions
  1232. };
  1233.  
  1234. CL_Compositor *
  1235. fe_create_compositor(MWContext *context)
  1236. {
  1237.   int32 comp_width, comp_height;
  1238.   CL_Drawable *cl_window_drawable, *cl_backing_store_drawable;
  1239.   CL_Compositor *compositor;
  1240.   fe_Drawable *window_drawable, *backing_store_drawable;
  1241.   Window window;
  1242.  
  1243.   Visual *visual;
  1244.  
  1245.   window = XtWindow(CONTEXT_DATA(context)->drawing_area);
  1246.   visual = fe_globalData.default_visual;
  1247.   backing_store_depth = fe_VisualDepth (fe_display, visual);
  1248.  
  1249.   /* Create a new compositor and its default layers */
  1250.   comp_width = CONTEXT_DATA(context)->scrolled_width;
  1251.   comp_height = CONTEXT_DATA(context)->scrolled_height;
  1252.  
  1253.   if (CONTEXT_DATA(context)->vscroll && 
  1254.       XtIsManaged(CONTEXT_DATA(context)->vscroll))
  1255.     comp_width -= CONTEXT_DATA(context)->sb_w;
  1256.   if (CONTEXT_DATA(context)->hscroll &&
  1257.       XtIsManaged(CONTEXT_DATA(context)->hscroll))
  1258.     comp_height -= CONTEXT_DATA(context)->sb_h;
  1259.  
  1260.   window_drawable = XP_NEW_ZAP(fe_Drawable);
  1261.   if (!window_drawable)
  1262.     return NULL;
  1263.   window_drawable->xdrawable = window;
  1264.  
  1265.   /* Create backing store drawable, but don't create pixmap
  1266.      until fe_set_drawable_dimensions() is called from the
  1267.      compositor */
  1268.   backing_store_drawable = XP_NEW_ZAP(fe_Drawable);
  1269.   if (!backing_store_drawable)
  1270.     return NULL;
  1271.  
  1272.   /* Create XP handle to window's HTML view for compositor */
  1273.   cl_window_drawable = CL_NewDrawable(comp_width, comp_height, 
  1274.                       CL_WINDOW, &window_drawable_vtable,
  1275.                       (void*)window_drawable);
  1276.  
  1277.   /* Create XP handle to backing store for compositor */
  1278.   cl_backing_store_drawable = CL_NewDrawable(comp_width, comp_height, 
  1279.                          CL_BACKING_STORE,
  1280.                          &backing_store_drawable_vtable,
  1281.                          (void*)backing_store_drawable);
  1282.  
  1283.   compositor = CL_NewCompositor(cl_window_drawable, cl_backing_store_drawable,
  1284.                 0, 0, comp_width, comp_height, 15);
  1285.  
  1286.   /* Set reasonable default drawable */
  1287.   CONTEXT_DATA (context)->drawable = window_drawable;
  1288.  
  1289.   return compositor;
  1290. }
  1291.  
  1292. /* Create and initialize the Image Library JMC callback interface.
  1293.    Also create an IL_GroupContext for the current context. */
  1294. XP_Bool
  1295. fe_init_image_callbacks(MWContext *context)
  1296. {
  1297.     IL_GroupContext *img_cx;
  1298.     IMGCB* img_cb;
  1299.     JMCException *exc = NULL;
  1300.  
  1301.     if (!context->img_cx) {
  1302.         PRBool observer_added_p;
  1303.         
  1304.         img_cb = IMGCBFactory_Create(&exc); /* JMC Module */
  1305.         if (exc) {
  1306.             JMC_DELETE_EXCEPTION(&exc); /* XXXM12N Should really return
  1307.                                            exception */
  1308.             return FALSE;
  1309.         }
  1310.  
  1311.         /* Create an Image Group Context.  IL_NewGroupContext augments the
  1312.            reference count for the JMC callback interface.  The opaque argument
  1313.            to IL_NewGroupContext is the Front End's display context, which will
  1314.            be passed back to all the Image Library's FE callbacks. */
  1315.         img_cx = IL_NewGroupContext((void*)context, (IMGCBIF *)img_cb);
  1316.  
  1317.         /* Attach the IL_GroupContext to the FE's display context. */
  1318.         context->img_cx = img_cx;
  1319.  
  1320.         /* Add an image group observer to the IL_GroupContext. */
  1321.         observer_added_p = IL_AddGroupObserver(img_cx, fe_ImageGroupObserver,
  1322.                                                (void *)context);
  1323.     }
  1324.     return TRUE;
  1325. }
  1326.  
  1327. /* in src/context_funcs.cpp */
  1328. extern MWContext *xfe2_MakeNewWindow(Widget, MWContext*, URL_Struct*,
  1329.                                      char *,MWContextType, Boolean, Chrome*);
  1330.  
  1331. MWContext *
  1332. fe_MakeNewWindow(Widget toplevel, MWContext *context_to_copy,
  1333.             URL_Struct *url, char *window_name, MWContextType type,
  1334.             Boolean skip_get_url, Chrome *decor)
  1335. {
  1336.   MWContext* context;
  1337.   struct fe_MWContext_cons *cons;
  1338.   fe_ContextData *fec;
  1339.   Widget shell;
  1340.   char *shell_name;
  1341.  
  1342.   int delete_response;
  1343.   Boolean allow_resize;
  1344.   Boolean is_modal;
  1345.   Boolean context_displays_html_p = False;
  1346.   Arg av[20];
  1347.   int ac;
  1348.   int16 new_charset;
  1349.  
  1350.   new_charset = CS_DEFAULT;
  1351.  
  1352.   /* Fix type */
  1353.   if (url && (type != MWContextSaveToDisk) && (type != MWContextBookmarks) &&
  1354.     (type != MWContextAddressBook) && (type != MWContextDialog)) {
  1355. #ifdef MOZ_MAIL_NEWS
  1356.     if (MSG_RequiresMailWindow (url->address) || MSG_RequiresNewsWindow(url->address))
  1357.       type = MWContextMail;
  1358.     else if (MSG_RequiresBrowserWindow (url->address)) {
  1359.       if (type != MWContextEditor)
  1360. #else
  1361.     {
  1362. #endif
  1363.     type = MWContextBrowser;
  1364.     }
  1365.   }
  1366.  
  1367.   return xfe2_MakeNewWindow(toplevel, context_to_copy, url, window_name,
  1368.                             type, skip_get_url, decor);
  1369. }
  1370.  
  1371.  
  1372. MWContext *
  1373. FE_MakeNewWindow(MWContext  *old_context,
  1374.          URL_Struct *url,
  1375.          char       *window_name,
  1376.          Chrome     *chrome)
  1377. {
  1378.   MWContext *   new_context;
  1379.   MWContextType type = MWContextBrowser;
  1380.  
  1381.   if ( (old_context == NULL)
  1382.        || (CONTEXT_WIDGET (old_context) == NULL) )
  1383.     return(NULL);
  1384.  
  1385.   if (chrome && chrome->type != 0)
  1386.     type = chrome->type;
  1387.  
  1388.   /*
  1389.    * Dependent Windows
  1390.    */
  1391.   if (chrome && chrome->dependent)
  1392.     {
  1393.       /*
  1394.        * Ensure that a dependent list exists, returning NULL
  1395.        * if one cannot be created.
  1396.        */
  1397.       if (old_context->js_dependent_list == 0)
  1398.     {
  1399.       XP_List * list;
  1400.       list = XP_ListNew();
  1401.       if (!list)
  1402.         return NULL;
  1403.       old_context->js_dependent_list = list;
  1404.     }
  1405.     }
  1406.  
  1407.   new_context = fe_MakeNewWindow (XtParent(CONTEXT_WIDGET (old_context)),
  1408.                   old_context, url,
  1409.                   window_name, type, (url == NULL), chrome);
  1410.  
  1411.   if (chrome && chrome->dependent)
  1412.     {
  1413.       /* parent knows about dependent */
  1414.       XP_ListAddObject(old_context->js_dependent_list, new_context);
  1415.       /* dependent knows about parent */
  1416.       new_context->js_parent = old_context;
  1417.     }
  1418.  
  1419.   return(new_context);
  1420. }
  1421.  
  1422. MWContext *
  1423. FE_MakeBlankWindow(MWContext *old_context, URL_Struct *url, char *window_name)
  1424. {
  1425.     MWContext *new_context;
  1426.  
  1427.     if ((old_context == NULL)||(CONTEXT_WIDGET (old_context) == NULL))
  1428.     {
  1429.         return(NULL);
  1430.     }
  1431.  
  1432.     new_context = fe_MakeWindow (
  1433.         XtParent(CONTEXT_WIDGET (old_context)),
  1434.         old_context, NULL, window_name, MWContextBrowser, TRUE);
  1435.     return(new_context);
  1436. }
  1437.  
  1438.  
  1439. void
  1440. FE_SetWindowLoading(MWContext *context, URL_Struct *url,
  1441.     Net_GetUrlExitFunc **exit_func_p)
  1442. {
  1443.     if ((context != NULL)&&(url != NULL))
  1444.     {
  1445.         fe_GetURL (context, url, TRUE);
  1446.         *exit_func_p = (Net_GetUrlExitFunc *)fe_url_exit;
  1447.     }
  1448. }
  1449.  
  1450.  
  1451. Boolean
  1452. fe_IsGridParent (MWContext *context)
  1453. {
  1454.   return (context->grid_children && XP_ListTopObject (context->grid_children));
  1455. }
  1456.  
  1457.  
  1458. MWContext *
  1459. fe_GetFocusGridOfContext(MWContext *context)
  1460. {
  1461.   MWContext *child;
  1462.   int i = 1;
  1463.  
  1464.   if (context == NULL)
  1465.     return 0;
  1466.  
  1467.   /* grid_children keeps a list of html frames...
  1468.      it's possible that it is null when there is no html frames created */
  1469.   if ( !context->grid_children) return 0;
  1470.  
  1471.   while ((child = (MWContext*)XP_ListGetObjectNum (context->grid_children,
  1472.                            i++))) {
  1473.     if (CONTEXT_DATA (child)->focus_grid)
  1474.       return child;
  1475.  
  1476.     if (fe_IsGridParent (child)) {
  1477.       child = fe_GetFocusGridOfContext (child);
  1478.       if (child != NULL)
  1479.     return child;
  1480.     }
  1481.   }
  1482.   return 0;
  1483. }
  1484.  
  1485. void
  1486. fe_MochaFocusNotify (MWContext *context, LO_Element *element)
  1487. {
  1488.     JSEvent *event;
  1489.     event = XP_NEW_ZAP(JSEvent);
  1490.     event->type = EVENT_FOCUS;
  1491.     ET_SendEvent (context, element, event, NULL, NULL);
  1492. }
  1493.  
  1494. void
  1495. fe_MochaBlurNotify (MWContext *context, LO_Element *element)
  1496. {
  1497.     JSEvent *event;
  1498.     event = XP_NEW_ZAP(JSEvent);
  1499.     event->type = EVENT_BLUR;
  1500.     ET_SendEvent (context, element, event, NULL, NULL);
  1501. }
  1502.  
  1503. void
  1504. fe_SetGridFocus (MWContext *context)
  1505. {
  1506.   Widget w;
  1507.   MWContext *top, *focus_grid;
  1508.   Dimension border_width;
  1509.  
  1510.   if (context == NULL)
  1511.     return;
  1512.  
  1513.   /* focus the new guy */
  1514.   fe_MochaFocusNotify (context, NULL);
  1515.  
  1516.   top = XP_GetNonGridContext (context);
  1517.   if (top == NULL)
  1518.     return;
  1519.  
  1520.   if ((focus_grid = fe_GetFocusGridOfContext (top))) {
  1521.     /* blur the previous guy */
  1522.     fe_MochaBlurNotify (focus_grid, NULL);
  1523.  
  1524.     CONTEXT_DATA (focus_grid)->focus_grid = False;
  1525.     w = CONTEXT_DATA (focus_grid)->main_pane;
  1526.     XtVaGetValues (w, XmNborderWidth, &border_width, 0);
  1527.     if (border_width)
  1528.       XtVaSetValues (w, XmNborderColor, 
  1529.              (CONTEXT_DATA (context)->default_bg_pixel), 0);
  1530.   }
  1531.  
  1532.   /* Then indicate which cell has focus */
  1533.   TRACEMSG (("context: 0x%x has focus\n", context));
  1534.  
  1535.   CONTEXT_DATA (context)->focus_grid = True;
  1536.   w = CONTEXT_DATA (context)->main_pane;
  1537.  
  1538.   XtVaGetValues (w, XmNborderWidth, &border_width, 0);
  1539.   if (border_width)
  1540.     XtVaSetValues (w, XmNborderColor,
  1541.            CONTEXT_DATA (context)->default_fg_pixel, 0);
  1542.  
  1543.   XFE_SetDocTitle (context, 0);
  1544. }
  1545.  
  1546. MWContext *
  1547. #ifdef XP_UNIX
  1548. FE_MakeGridWindow (MWContext *old_context, void *hist_list, void *history,
  1549.     int32 x, int32 y,
  1550. #else
  1551. FE_MakeGridWindow (MWContext *old_context, void *history, int32 x, int32 y,
  1552. #endif /* XP_UNIX */
  1553.         int32 width, int32 height, char *url_str, char *window_name,
  1554.     int8 scrolling, NET_ReloadMethod force_reload, Bool no_edge)
  1555. {
  1556.   Widget parent = CONTEXT_DATA (old_context)->drawing_area;
  1557.   MWContext *context = XP_NewContext();
  1558.   struct fe_MWContext_cons *cons = (struct fe_MWContext_cons *)
  1559.     malloc (sizeof (struct fe_MWContext_cons));
  1560.   fe_ContextData *fec = (fe_ContextData *) calloc (sizeof (fe_ContextData), 1);
  1561.   History_entry *he = (History_entry *)history;
  1562.   URL_Struct *url = NULL;
  1563.  
  1564.   CONTEXT_DATA (context) = fec;
  1565.  
  1566.   /* add the layout function pointers
  1567.    */
  1568.   context->funcs = fe_BuildDisplayFunctionTable();
  1569.   context->convertPixX = context->convertPixY = 1;
  1570.   context->is_grid_cell = TRUE;
  1571.   context->grid_parent = old_context;
  1572.  
  1573.   /* New field added by putterman for increase/decrease font */
  1574.   context->fontScalingPercentage = old_context->fontScalingPercentage;
  1575.  
  1576.   cons->context = context;
  1577.   cons->next = fe_all_MWContexts;
  1578.   fe_all_MWContexts = cons;
  1579.  
  1580.   /* pixelsPerPoint:  display-specific information needed by the back end
  1581.    * when converting style sheet length units between points and pixels.
  1582.    */
  1583.   context->XpixelsPerPoint = old_context->XpixelsPerPoint;
  1584.   context->YpixelsPerPoint = old_context->YpixelsPerPoint;
  1585.  
  1586.   SHIST_InitSession (context);        /* Initialize the history library. */
  1587. #ifdef XP_UNIX
  1588.   if (hist_list != NULL)
  1589.   {
  1590.     context->hist.list_ptr = hist_list;
  1591.   }
  1592.   else
  1593.   {
  1594.     SHIST_AddDocument(context, he);
  1595.   }
  1596. #else
  1597.   SHIST_AddDocument(context, he);
  1598. #endif /* XP_UNIX */
  1599.  
  1600.   if (he)
  1601.     url = SHIST_CreateURLStructFromHistoryEntry (context, he);
  1602.   else
  1603.     url = NET_CreateURLStruct (url_str, NET_DONT_RELOAD);
  1604.  
  1605.   if (url) {
  1606.     MWContext *top = XP_GetNonGridContext(old_context);
  1607.     History_entry *h = SHIST_GetCurrent (&top->hist);
  1608.  
  1609.     url->force_reload = force_reload;
  1610.  
  1611.     /* Set the referer field in the url to the document that refered to the
  1612.      * grid parent.  New function fe_GetURLForReferral() might be used
  1613.      * here, brendan says this is probably Ok. -mcafee
  1614.      */
  1615.     if (h && h->referer)
  1616.       url->referer = strdup(h->referer);
  1617.   }
  1618.  
  1619.   if (window_name)
  1620.     {
  1621.       context->name = strdup (window_name);
  1622.     }
  1623.   XP_AddContextToList (context);
  1624.  
  1625.   if (old_context)
  1626.     {
  1627.       CONTEXT_DATA (context)->autoload_images_p =
  1628.         CONTEXT_DATA (old_context)->autoload_images_p;
  1629.       CONTEXT_DATA (context)->loading_images_p = False;
  1630.       CONTEXT_DATA (context)->looping_images_p = False;
  1631.       CONTEXT_DATA (context)->delayed_images_p =
  1632.         CONTEXT_DATA (old_context)->delayed_images_p;
  1633.       CONTEXT_DATA (context)->force_load_images = 0;
  1634.       CONTEXT_DATA (context)->fancy_ftp_p =
  1635.         CONTEXT_DATA (old_context)->fancy_ftp_p;
  1636.       CONTEXT_DATA (context)->xfe_doc_csid =
  1637.         CONTEXT_DATA (old_context)->xfe_doc_csid;
  1638.     }
  1639.   CONTEXT_WIDGET (context) = CONTEXT_WIDGET (old_context);
  1640.   CONTEXT_DATA (context)->backdrop_pixmap = (Pixmap) ~0;
  1641.   CONTEXT_DATA (context)->grid_scrolling = scrolling;
  1642.  
  1643.   /* FRAMES_HAVE_THEIR_OWN_COLORMAP was an unfinished
  1644.      experiment by kevina. */
  1645. #ifdef FRAMES_HAVE_THEIR_OWN_COLORMAP
  1646.   /* We have to go through this to get the toplevel widget */
  1647.   {
  1648.       MWContext *top_context = XP_GetNonGridContext(context);
  1649.  
  1650.       fe_pick_visual_and_colormap (XtParent(CONTEXT_WIDGET (top_context)),
  1651.                                    context);
  1652.   }
  1653. #else
  1654.   /* Inherit colormap from our parent */
  1655.   CONTEXT_DATA(context)->colormap = CONTEXT_DATA(old_context)->colormap;
  1656. #endif
  1657.  
  1658. #ifdef FRAMES_HAVE_THEIR_OWN_COLORMAP
  1659.         /* XXXM12N Create and initialize the Image Library JMC callback
  1660.            interface.  Also create a new IL_GroupContext for this window.*/
  1661.         if (!fe_init_image_callbacks(context))
  1662.             {
  1663.                 return NULL;
  1664.             }
  1665.   fe_InitColormap(context);
  1666. #endif
  1667.  
  1668.   XtGetApplicationResources (CONTEXT_WIDGET (old_context),
  1669.                              (XtPointer) CONTEXT_DATA (context),
  1670.                              fe_Resources, fe_ResourcesSize,
  1671.                              0, 0);
  1672.  
  1673. /* CONTEXT_DATA (context)->main_pane = parent; */
  1674.  
  1675.   /*
  1676.    * set the default coloring correctly into the new context.
  1677.    */
  1678.   {
  1679.     Pixel unused_select_pixel;
  1680.     XmGetColors (XtScreen (parent),
  1681.          fe_cmap(context),
  1682.          CONTEXT_DATA (context)->default_bg_pixel,
  1683.          &(CONTEXT_DATA (context)->fg_pixel),
  1684.          &(CONTEXT_DATA (context)->top_shadow_pixel),
  1685.          &(CONTEXT_DATA (context)->bottom_shadow_pixel),
  1686.          &unused_select_pixel);
  1687.   }
  1688.  
  1689.   /* ### Create a form widget to parent the scroller.
  1690.    *
  1691.    * This might keep the scroller from becoming smaller than
  1692.    * the cell size when there are no scrollbars.
  1693.    */
  1694.  
  1695.   {
  1696.     Arg av [50];
  1697.     int ac;
  1698.     Widget pane, mainw, scroller;
  1699.     int border_width = 0;
  1700.  
  1701.     if (no_edge)
  1702.       border_width = 0;
  1703.     else
  1704.       border_width = 2;
  1705.  
  1706.     ac = 0;
  1707.     XtSetArg (av[ac], XmNx, (Position)x); ac++;
  1708.     XtSetArg (av[ac], XmNy, (Position)y); ac++;
  1709.     XtSetArg (av[ac], XmNwidth, (Dimension)width - 2*border_width); ac++;
  1710.     XtSetArg (av[ac], XmNheight, (Dimension)height - 2*border_width); ac++;
  1711.     XtSetArg (av[ac], XmNborderWidth, border_width); ac++;
  1712.     mainw = XmCreateForm (parent, "form", av, ac);
  1713.  
  1714.     ac = 0;
  1715.     XtSetArg (av[ac], XmNborderWidth, 0); ac++;
  1716.     XtSetArg (av[ac], XmNmarginWidth, 0); ac++;
  1717.     XtSetArg (av[ac], XmNmarginHeight, 0); ac++;
  1718.     XtSetArg (av[ac], XmNborderColor,
  1719.               CONTEXT_DATA (context)->default_bg_pixel); ac++;
  1720.     pane = XmCreatePanedWindow (mainw, "pane", av, ac);
  1721.  
  1722.     XtVaSetValues (pane,
  1723.            XmNtopAttachment, XmATTACH_FORM,
  1724.            XmNbottomAttachment, XmATTACH_FORM,
  1725.            XmNleftAttachment, XmATTACH_FORM,
  1726.            XmNrightAttachment, XmATTACH_FORM,
  1727.            0);
  1728.  
  1729.     /* The actual work area */
  1730.     scroller = fe_MakeScrolledWindow (context, pane, "scroller");
  1731.     XtVaSetValues (CONTEXT_DATA (context)->scrolled,
  1732.            XmNborderWidth, 0, 0);
  1733.  
  1734.     XtManageChild (scroller);
  1735.     XtManageChild (pane);
  1736.     XtManageChild (mainw);
  1737.  
  1738.     CONTEXT_DATA (context)->main_pane = mainw;
  1739.   }
  1740.  
  1741.   fe_load_default_font (context);
  1742.   fe_get_context_resources (context);   /* Do other resource db hackery. */
  1743.  
  1744.   /* FIXME - This is flagrantly wasteful of backing store memory.
  1745.      Contexts which are not leaves in the FRAMESET hierarchy don't
  1746.      need any backing store or compositor. */
  1747.   context->compositor = fe_create_compositor(context);
  1748.  
  1749.   /* Figure out how much space the horizontal and vertical scrollbars take up.
  1750.      It's basically impossible to determine this before creating them...
  1751.    */
  1752.   {
  1753.     Dimension w1 = 0, w2 = 0, h1 = 0, h2 = 0;
  1754.  
  1755.     XtManageChild (CONTEXT_DATA (context)->hscroll);
  1756.     XtManageChild (CONTEXT_DATA (context)->vscroll);
  1757.     XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  1758.                                  XmNwidth, &w1,
  1759.                                  XmNheight, &h1,
  1760.                                  0);
  1761.  
  1762.     XtUnmanageChild (CONTEXT_DATA (context)->hscroll);
  1763.     XtUnmanageChild (CONTEXT_DATA (context)->vscroll);
  1764.     XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  1765.                                  XmNwidth, &w2,
  1766.                                  XmNheight, &h2,
  1767.                                  0);
  1768.  
  1769.     CONTEXT_DATA (context)->sb_w = w2 - w1;
  1770.     CONTEXT_DATA (context)->sb_h = h2 - h1;
  1771.  
  1772.     /* Now that we know, we don't need to leave them managed. */
  1773.   }
  1774.  
  1775.   XtVaSetValues (CONTEXT_DATA (context)->scrolled, XmNinitialFocus,
  1776.                  CONTEXT_DATA (context)->drawing_area, 0);
  1777.  
  1778.   fe_SetGridFocus (context);  /* Give this grid focus */
  1779.   fe_InitScrolling (context); /* big voodoo */
  1780.  
  1781.   /* XXXM12N Create and initialize the Image Library JMC callback
  1782.      interface.  Also create a new IL_GroupContext for this window.*/
  1783.   if (!context->img_cx)
  1784.       if (!fe_init_image_callbacks(context))
  1785.           {
  1786.               return NULL;
  1787.           }
  1788.  
  1789.   fe_InitColormap (context);
  1790.  
  1791.   if (url)
  1792.     {
  1793.       /* #### This might not be right, or there might be more that needs
  1794.          to be done...   Note that url->history_num is bogus for the new
  1795.          context.  url->position_tag might also be context-specific. */
  1796. #ifdef XP_UNIX
  1797.       /*
  1798.        * I believe that if we are restoring from a history entry,
  1799.        * we don't want to clear this saved data.
  1800.        */
  1801.       if (!he)
  1802.       {
  1803.         XP_MEMSET (&url->savedData, 0, sizeof (SHIST_SavedData));
  1804.       }
  1805. #else
  1806.       XP_MEMSET (&url->savedData, 0, sizeof (SHIST_SavedData));
  1807. #endif /* XP_UNIX */
  1808.       fe_GetURL (context, url, FALSE);
  1809.     }
  1810.  
  1811.   XFE_SetDocTitle (context, 0);
  1812.   CONTEXT_DATA (context)->are_scrollbars_active = True;
  1813.  
  1814.   return(context);
  1815. }
  1816.  
  1817. void
  1818. FE_RestructureGridWindow (MWContext *context, int32 x, int32 y,
  1819.         int32 width, int32 height)
  1820. {
  1821.   Widget mainw;
  1822.  
  1823.   /*
  1824.    * This comes from blank frames.  Maybe we should clear them
  1825.    * before we return?
  1826.    */
  1827.   if (!context ) return;
  1828.  
  1829.   /*
  1830.    * Basically we just set the new position and dimensions onto the
  1831.    * parent of the drawing area.  X will do the rest for us.
  1832.    * Because of the window gravity side effects of guffaws scrolling
  1833.    * The drawing area won't move with its parent unless we temporarily
  1834.    * turn off guffaws.
  1835.    */
  1836.   mainw = CONTEXT_DATA (context)->main_pane;
  1837.   fe_SetGuffaw(context, FALSE);
  1838.   XtVaSetValues (mainw,
  1839.          XmNx, (Position)x,
  1840.          XmNy, (Position)y,
  1841.          XmNwidth, (Dimension)width - 4,   /* Adjust for focus border */
  1842.          XmNheight, (Dimension)height - 4,
  1843.          0);
  1844.   fe_SetGuffaw(context, TRUE);
  1845. }
  1846.  
  1847. /* Required to make custom colormap installation work.
  1848.    Really, not *every* context has a private colormap.
  1849.    Trivial contexts like address book, bookmarks, etc.
  1850.    share a colormap. */
  1851. #define EVERY_CONTEXT_HAS_PRIVATE_COLORMAP
  1852.  
  1853. static void
  1854. fe_pick_visual_and_colormap (Widget toplevel, MWContext *new_context)
  1855. {
  1856.   Screen *screen = XtScreen (toplevel);
  1857.   Display *dpy = XtDisplay (toplevel);
  1858.   Colormap cmap;
  1859.   Visual *v;
  1860.   fe_colormap *colormap;
  1861.  
  1862.   v = fe_globalData.default_visual;
  1863.   if (!v)
  1864.   {
  1865.     String str = 0;
  1866.     /* "*visualID" is special for a number of reasons... */
  1867.     static XtResource res = { "visualID", "VisualID",
  1868.                   XtRString, sizeof (String),
  1869.                   0, XtRString, "default" };
  1870.     XtGetSubresources (toplevel, &str, (char *) fe_progname, "TopLevelShell",
  1871.                &res, 1, 0, 0);
  1872.     v = fe_ParseVisual (screen, str);
  1873.     fe_globalData.default_visual = v;
  1874.   }
  1875.  
  1876.   {
  1877.     String str = 0;
  1878.     static XtResource res = { "installColormap", XtCString, XtRString,
  1879.                   sizeof (String), 0, XtRString, "guess" };
  1880.     XtGetApplicationResources (toplevel, &str, &res, 1, 0, 0);
  1881.     if (!str || !*str || !XP_STRCASECMP(str, "guess"))
  1882.       {
  1883.     /* But everybody lies about this value */
  1884.     char *vendor = XServerVendor (XtDisplay (toplevel));
  1885.     fe_globalData.always_install_cmap =
  1886.       !strcmp (vendor, "Silicon Graphics");
  1887.       }
  1888.     else if (!XP_STRCASECMP(str, "yes") || !XP_STRCASECMP(str, "true"))
  1889.       fe_globalData.always_install_cmap = True;
  1890.     else if (!XP_STRCASECMP(str, "no") || !XP_STRCASECMP(str, "false"))
  1891.       fe_globalData.always_install_cmap = False;
  1892.     else
  1893.       {
  1894.     fprintf (stderr,
  1895.          XP_GetString(XFE_DISPLAY_FACTORY_INSTALL_COLORMAP_ERROR),
  1896.          fe_progname, str);
  1897.     fe_globalData.always_install_cmap = False;
  1898.       }
  1899.   }
  1900.  
  1901.   /* Don't allow colormap flashing on a deep display */
  1902.   if (v != DefaultVisualOfScreen (screen))
  1903.     fe_globalData.always_install_cmap = True;
  1904.   
  1905.   if (!fe_globalData.default_colormap)
  1906.     {
  1907.       cmap = DefaultColormapOfScreen (screen);
  1908.       fe_globalData.default_colormap =
  1909.           fe_NewColormap(screen,  DefaultVisualOfScreen (screen), cmap, False);
  1910.     }
  1911.  
  1912.   colormap = fe_globalData.common_colormap;
  1913.  
  1914.   if (!colormap)
  1915.     {
  1916.       if (fe_globalData.always_install_cmap)
  1917.         {
  1918.           /* Create a colormap for "simple" contexts 
  1919.              like bookmarks, address book, etc */
  1920.           cmap = XCreateColormap (dpy, RootWindowOfScreen (screen),
  1921.                                   v, AllocNone);
  1922.           colormap = fe_NewColormap(screen, v, cmap, True);
  1923.         }
  1924.       else
  1925.         {
  1926.           /* Use the default colormap for all contexts. */
  1927.           colormap = fe_globalData.default_colormap;
  1928.         }
  1929.       fe_globalData.common_colormap = colormap;
  1930.     }
  1931.   
  1932.       
  1933. #ifdef EVERY_CONTEXT_HAS_PRIVATE_COLORMAP
  1934.   if (fe_globalData.always_install_cmap)
  1935.     {
  1936.       /* Even when installing "private" colormaps for every window,
  1937.          "simple" contexts, which have fixed color composition, share
  1938.          a single colormap. */
  1939.       MWContextType type = new_context->type;
  1940.       if ((type == MWContextBrowser) ||
  1941.           (type == MWContextEditor)  ||
  1942.           (type == MWContextNews)    ||
  1943.           (type == MWContextMail))
  1944.         {
  1945.           cmap = XCreateColormap (dpy, RootWindowOfScreen (screen),
  1946.                                   v, AllocNone);
  1947.           colormap = fe_NewColormap(screen, v, cmap, True);
  1948.         }
  1949.     }
  1950. #endif  /* !EVERY_CONTEXT_HAS_PRIVATE_COLORMAP */
  1951.  
  1952.   CONTEXT_DATA (new_context)->colormap = colormap;
  1953. }
  1954.  
  1955. void
  1956. fe_InitializeGlobalResources (Widget toplevel)
  1957. {
  1958.   XtGetApplicationResources (toplevel,
  1959.                  (XtPointer) &fe_globalData,
  1960.                  fe_GlobalResources, fe_GlobalResourcesSize,
  1961.                  0, 0);
  1962.  
  1963.   /*
  1964.    *    And then there was Sun. Try to detect losing olwm,
  1965.    *    and default to mono desktop icons.
  1966.    */
  1967.   if (fe_globalData.wm_icon_policy == NULL) { /* not set */
  1968.       if (XfeIsOpenLookRunning(toplevel))
  1969.       fe_globalData.wm_icon_policy = "mono";
  1970.       else
  1971.       fe_globalData.wm_icon_policy = "color";
  1972.   }
  1973.     
  1974.   /* Add a timer to periodically flush out the global history and bookmark. */
  1975.   fe_save_history_timer ((XtPointer) ((int) True), 0);
  1976.  
  1977.   /* #### move to prefs */
  1978.   LO_SetUserOverride (!fe_globalData.document_beats_user_p);
  1979. }
  1980.  
  1981.  
  1982. /* This initializes resources which must be set up BEFORE the widget is
  1983.    realized or managed (sizes and things). */
  1984. void
  1985. fe_get_context_resources (MWContext *context)
  1986. {
  1987.   fe_ContextData *fec = CONTEXT_DATA (context);
  1988.   if (fec->drawing_area) {
  1989.     XtVaGetValues (fec->drawing_area,
  1990.            XmNbackground, &fec->bg_pixel, 0);
  1991.   } /* else??? ### */
  1992.  
  1993.   /* If the selection colors ended up mapping to the same pixel values,
  1994.      invert them. */
  1995.   if (CONTEXT_DATA (context)->select_fg_pixel ==
  1996.       CONTEXT_DATA (context)->fg_pixel &&
  1997.       CONTEXT_DATA (context)->select_bg_pixel ==
  1998.       CONTEXT_DATA (context)->bg_pixel)
  1999.     {
  2000.       CONTEXT_DATA (context)->select_fg_pixel =
  2001.     CONTEXT_DATA (context)->bg_pixel;
  2002.       CONTEXT_DATA (context)->select_bg_pixel =
  2003.     CONTEXT_DATA (context)->fg_pixel;
  2004.     }
  2005.  
  2006.   /* Tell layout about the default colors and background.
  2007.    */
  2008.   {
  2009.     XColor c[5];
  2010.     c[0].pixel = CONTEXT_DATA (context)->link_pixel;
  2011.     c[1].pixel = CONTEXT_DATA (context)->vlink_pixel;
  2012.     c[2].pixel = CONTEXT_DATA (context)->alink_pixel;
  2013.     c[3].pixel = CONTEXT_DATA (context)->default_fg_pixel;
  2014.     c[4].pixel = CONTEXT_DATA (context)->default_bg_pixel;
  2015.     XQueryColors (XtDisplay (CONTEXT_WIDGET (context)),
  2016.           fe_cmap(context),
  2017.           c, 5);
  2018.     LO_SetDefaultColor (LO_COLOR_LINK,
  2019.             c[0].red >> 8, c[0].green >> 8, c[0].blue >> 8);
  2020.     LO_SetDefaultColor (LO_COLOR_VLINK,
  2021.             c[1].red >> 8, c[1].green >> 8, c[1].blue >> 8);
  2022.     LO_SetDefaultColor (LO_COLOR_ALINK,
  2023.             c[2].red >> 8, c[2].green >> 8, c[2].blue >> 8);
  2024.     LO_SetDefaultColor (LO_COLOR_FG,
  2025.             c[3].red >> 8, c[3].green >> 8, c[3].blue >> 8);
  2026.     LO_SetDefaultColor (LO_COLOR_BG,
  2027.             c[4].red >> 8, c[4].green >> 8, c[4].blue >> 8);
  2028.  
  2029.     if (CONTEXT_DATA (context)->default_background_image &&
  2030.     *CONTEXT_DATA (context)->default_background_image)
  2031.       {
  2032.     char *bi = CONTEXT_DATA (context)->default_background_image;
  2033.     if (bi[0] == '/')
  2034.       {
  2035.         char *s = (char *) malloc (XP_STRLEN(bi) + 6);
  2036.         strcpy (s, "file:");
  2037.         strcat (s, bi);
  2038.         LO_SetDefaultBackdrop (s);
  2039.         free (s);
  2040.       }
  2041.     else
  2042.       {
  2043.         LO_SetDefaultBackdrop (bi);
  2044.       }
  2045.       }
  2046.   }
  2047. }
  2048.  
  2049.  
  2050. void
  2051. fe_set_scrolled_default_size(MWContext *context)
  2052. {
  2053.     /* Set the default size of the scrolling area based on the size of the
  2054.        default font.  (This can be overridden by a -geometry argument.)
  2055.        */
  2056.     int16 charset = CS_LATIN1;
  2057.     fe_Font font = fe_LoadFontFromFace(context, NULL, &charset, 0, 3, 0);
  2058.     Widget scrolled = XtNameToWidget (CONTEXT_WIDGET (context), "*scroller");
  2059.     unsigned int cw = (font ? default_char_width (CS_LATIN1, font) : 12);
  2060.     /* So just add 10% or so and hope it all fits. */
  2061.     Dimension w = (cw * 90);
  2062.     Dimension h = w;
  2063.  
  2064.     if (context->type == MWContextMessageComposition ) {
  2065.         /*
  2066.          * NOTE:  let's try to pick a smaller MailCompose window...
  2067.          */
  2068.         h = ( cw * 50 );
  2069.     }
  2070.  
  2071.     if (scrolled) {
  2072.         Dimension max_height = HeightOfScreen (XtScreen (scrolled));
  2073.         Dimension pseudo_max_height = 0;
  2074.  
  2075.         if (context->type == MWContextMessageComposition ) {
  2076.             pseudo_max_height = max_height * 0.50;
  2077.         }
  2078.         /* EDITOR & BROWSER...
  2079.          *
  2080.          * We don't want the default window size to be bigger than the screen.
  2081.          * So don't make the default height of the scrolling area be more than
  2082.          * 90% of the height of the screen.  This is pretty pseudo-nebulous,
  2083.          * but again, getting exact numbers here is a royal pain.
  2084.          */
  2085.         else {
  2086.             pseudo_max_height = max_height * 0.70;
  2087.         }
  2088.  
  2089.         if (h > pseudo_max_height)
  2090.             h = pseudo_max_height;
  2091.  
  2092.         XtVaSetValues (scrolled, XmNwidth, w, XmNheight, h, 0);
  2093.     }
  2094.   fe_DoneWithFont(font);
  2095. }
  2096.  
  2097.  
  2098. static void
  2099. fe_save_history_timer (XtPointer closure, XtIntervalId *id)
  2100. {
  2101.   Boolean init_only_p = (Boolean) ((int) closure);
  2102.   if (! init_only_p) {
  2103.     fe_SaveBookmarks ();
  2104.     GH_SaveGlobalHistory ();
  2105.     NET_WriteCacheFAT (0, False);
  2106.     NET_SaveCookies(NULL);
  2107.   }
  2108.   /* Re-add the timer. */
  2109.   fe_globalData.save_history_id =
  2110.     XtAppAddTimeOut (fe_XtAppContext,
  2111.              fe_globalData.save_history_interval * 1000,
  2112.              fe_save_history_timer, (XtPointer) ((int) False));
  2113. }
  2114.  
  2115.  
  2116. static void
  2117. fe_refresh_url_timer (XtPointer closure, XtIntervalId *id)
  2118. {
  2119.   MWContext *context = (MWContext *) closure;
  2120.   URL_Struct *url;
  2121.  
  2122.   CONTEXT_DATA (context)->refresh_url_timer = 0; /* clear */
  2123.  
  2124.   XP_ASSERT (CONTEXT_DATA (context)->refresh_url_timer_url);
  2125.  
  2126.   if (! CONTEXT_DATA (context)->refresh_url_timer_url)
  2127.     return;
  2128.   url = NET_CreateURLStruct (CONTEXT_DATA (context)->refresh_url_timer_url,
  2129.                  NET_NORMAL_RELOAD);
  2130.   url->force_reload = NET_NORMAL_RELOAD;
  2131.   fe_GetURL (context, url, FALSE);
  2132. }
  2133.  
  2134. void
  2135. FE_SetRefreshURLTimer (MWContext *context, uint32 secs, char *url)
  2136. {
  2137.   if(context->type != MWContextBrowser)
  2138.     return;
  2139.  
  2140.   if (CONTEXT_DATA (context)->refresh_url_timer)
  2141.     XtRemoveTimeOut (CONTEXT_DATA (context)->refresh_url_timer);
  2142.   if (CONTEXT_DATA (context)->refresh_url_timer_url)
  2143.     free (CONTEXT_DATA (context)->refresh_url_timer_url);
  2144.   CONTEXT_DATA (context)->refresh_url_timer = 0;
  2145.   CONTEXT_DATA (context)->refresh_url_timer_secs = secs;
  2146.   CONTEXT_DATA (context)->refresh_url_timer_url = strdup (url);
  2147.   if (secs <= 0)
  2148.     fe_refresh_url_timer ((XtPointer) context, 0);
  2149.   else
  2150.     CONTEXT_DATA (context)->refresh_url_timer =
  2151.       XtAppAddTimeOut (fe_XtAppContext, secs * 1000,
  2152.                fe_refresh_url_timer, (XtPointer) context);
  2153. }
  2154.  
  2155.  
  2156. /* This initializes resources which must be set up AFTER the widget is
  2157.    realized (meaning we need a window of the correct depth.) */
  2158. void
  2159. fe_get_final_context_resources (MWContext *context)
  2160. {
  2161.   static Boolean guffaws_done = False;
  2162.  
  2163.   fe_InitIcons (context, MSG_BIFF_Unknown);
  2164.  
  2165.   if (!guffaws_done)
  2166.     {
  2167.       Widget widget = CONTEXT_DATA (context)->drawing_area;
  2168.       if (widget) {
  2169.     if (! XtIsRealized (widget)) abort ();
  2170.     guffaws_done = True;
  2171.     fe_globalData.fe_guffaw_scroll =
  2172.       fe_WindowGravityWorks (CONTEXT_WIDGET(context), widget);
  2173.       }
  2174.     }
  2175. }
  2176.  
  2177. void
  2178. fe_DestroySaveToDiskContext(MWContext *context)
  2179. {
  2180.   fe_delete_cb (0, (XtPointer) context, 0);
  2181. }
  2182.  
  2183. void fe_cleanup_tooltips(MWContext *context);
  2184.  
  2185. void
  2186. fe_DestroyContext_part2(void *c)
  2187. {
  2188.     MWContext *context = (MWContext*)c;
  2189.  
  2190.   /* Destroy the compositor associated with the context. */
  2191.   if (context->compositor)
  2192.       {
  2193.           CL_DestroyCompositor(context->compositor);
  2194.           context->compositor = NULL;
  2195.       }
  2196.  
  2197. #ifdef MOZ_MAIL_NEWS
  2198.   MimeDestroyContextData(context);
  2199. #endif
  2200.  
  2201.   if (context->title) free (context->title);
  2202.   context->title = 0;
  2203.  
  2204.   /* If a synchronous url dialog is up, dont free the context. Once the
  2205.    * synchronous url dialog is over, we will free it.
  2206.    */
  2207.   if (fe_IsContextProtected(context)) {
  2208.     CONTEXT_DATA(context)->destroyed = 1;
  2209.   }
  2210.   else {
  2211.     free (CONTEXT_DATA (context));
  2212.     free (context);
  2213.   }
  2214. }
  2215.  
  2216. void
  2217. fe_DestroyContext (MWContext *context)
  2218. {
  2219.   PRBool observer_removed_p;    
  2220.   fe_ContextData* d = CONTEXT_DATA(context);
  2221.   Widget w = CONTEXT_WIDGET (context);
  2222.   struct fe_MWContext_cons *rest, *prev;
  2223.  
  2224.   /* Fix for bug #29631 */
  2225.   if (context == last_documented_xref_context)
  2226.     {
  2227.       last_documented_xref_context = 0;
  2228.       last_documented_xref = 0;
  2229.       last_documented_anchor_data = 0;
  2230.     }
  2231.  
  2232.   /* This is a hack. If the mailcompose window is going away and 
  2233.    * a tooltip was still there (or) was armed (a timer was set for it)
  2234.    * for a widget in the mailcompose window, then the destroying
  2235.    * mailcompose context would cause a core dump when the tooltip
  2236.    * timer hits. This could happen to a javascript window with toolbars
  2237.    * too if it is being closed on a timer.
  2238.    *
  2239.    * In this critical time of 3.x ship, we are fixing this by
  2240.    * always killing any tooltip that was present anywhere and 
  2241.    * remove the timer for any armed tooltop anywhere in the
  2242.    * navigator when any context is going away.
  2243.    *----
  2244.    * The proper thing to do would be
  2245.    *  - to check if the fe_tool_tips_widget is a child of the
  2246.    *    CONTEXT_WIDGET(context) and if it is, then cleanup the tooltip.
  2247.    */
  2248.   fe_cleanup_tooltips(context);
  2249.  
  2250.  
  2251.   if (context->is_grid_cell)
  2252.     CONTEXT_DATA (context)->being_destroyed = True;
  2253.  
  2254.   if (context->type == MWContextSaveToDisk) {
  2255.     /* We might be in an extend text selection on the text widgets.
  2256.        If we destroy this now, we will dump core. So before destroying
  2257.        we will disable extend of the selection. */
  2258.     XtCallActionProc(CONTEXT_DATA (context)->url_label, "extend-end",
  2259.                 NULL, NULL, 0);
  2260.     XtCallActionProc(CONTEXT_DATA (context)->url_text, "extend-end",
  2261.                 NULL, NULL, 0);
  2262.   }
  2263.  
  2264. #ifdef EDITOR
  2265.   if (context->type == MWContextEditor)
  2266.       fe_EditorCleanup(context);
  2267. #endif /*EDITOR*/
  2268.  
  2269.   if (context->is_grid_cell)
  2270.     w = d->main_pane;
  2271.   XP_InterruptContext (context);
  2272.   if (d->refresh_url_timer)
  2273.     XtRemoveTimeOut (d->refresh_url_timer);
  2274.  
  2275.   /* Progress takes a context, removing timeout */
  2276.   if (CONTEXT_DATA (context)->thermo_timer_id)
  2277.     {
  2278.         XtRemoveTimeOut (CONTEXT_DATA (context)->thermo_timer_id);
  2279.         
  2280.         CONTEXT_DATA (context)->thermo_timer_id = 0;
  2281.     }
  2282.  
  2283.   if (d->refresh_url_timer_url)
  2284.     free (d->refresh_url_timer_url);
  2285.   fe_DisposeColormap(context);
  2286.  
  2287.   /*
  2288.   ** We have to destroy the layout before calling XtUnmanageChild so that
  2289.   ** we have a chance to reparent the applet windows to a safe
  2290.   ** place. Otherwise they'll get destroyed.
  2291.   */
  2292.   fe_DestroyLayoutData (context);
  2293.   XtUnmanageChild (w);
  2294.  
  2295.   if (context->color_space) {
  2296.       IL_ReleaseColorSpace(context->color_space);
  2297.       context->color_space = NULL;
  2298.   }
  2299.  
  2300.   /* Destroy the image group context after removing the image group
  2301.      observer. */
  2302.   observer_removed_p =
  2303.       IL_RemoveGroupObserver(context->img_cx, fe_ImageGroupObserver,
  2304.                              (void *)context);
  2305.   IL_DestroyGroupContext(context->img_cx);
  2306.   context->img_cx = NULL;
  2307.  
  2308.   /* Fix for bug #29631 */
  2309.   if (context == last_documented_xref_context)
  2310.     {
  2311.       last_documented_xref_context = 0;
  2312.       last_documented_xref = 0;
  2313.       last_documented_anchor_data = 0;
  2314.     }
  2315.  
  2316.   fe_StopProgressGraph (context);
  2317.   fe_FindReset (context);
  2318.   SHIST_EndSession (context);
  2319.   fe_DisownSelection (context, 0, True);
  2320.   fe_DisownSelection (context, 0, False);
  2321.  
  2322.   if (! context->is_grid_cell) {
  2323.     if (context->type == MWContextSaveToDisk)
  2324.       XtRemoveCallback (w, XtNdestroyCallback, fe_AbortCallback, context);
  2325.     else
  2326.       XtRemoveCallback (w, XtNdestroyCallback, fe_delete_cb, context);
  2327.  
  2328.     XtRemoveEventHandler (w, StructureNotifyMask, False, fe_map_notify_eh,
  2329.               context);
  2330.  
  2331.      if (context->type == MWContextDialog) {
  2332.       XtRemoveEventHandler (w, FocusChangeMask, False, fe_focus_notify_eh, 
  2333.              context);
  2334.     }
  2335.   }
  2336.   XtDestroyWidget (w);
  2337.  
  2338.   if (CONTEXT_DATA (context)->ftd) free (CONTEXT_DATA (context)->ftd);
  2339.   if (CONTEXT_DATA (context)->sd) free (CONTEXT_DATA (context)->sd);
  2340.   if (CONTEXT_DATA(context)->find_data)
  2341.     XP_FREE(CONTEXT_DATA(context)->find_data);
  2342.  
  2343.   for (prev = 0, rest = fe_all_MWContexts;
  2344.        rest;
  2345.        prev = rest, rest = rest->next)
  2346.     if (rest->context == context)
  2347.       break;
  2348.   if (! rest) abort ();
  2349.   if (prev)
  2350.     prev->next = rest->next;
  2351.   else
  2352.     fe_all_MWContexts = rest->next;
  2353.   free (rest);
  2354.  
  2355.  
  2356.   /* Some window disappears. So we need to recreate windows menu of all
  2357.      contexts availables. Mark so. */
  2358.   for( rest=fe_all_MWContexts; rest; rest=rest->next )
  2359.     CONTEXT_DATA(rest->context)->windows_menu_up_to_date_p = False;
  2360.  
  2361. #ifdef JAVA
  2362.   LJ_DiscardEventsForContext(context);
  2363. #endif /* JAVA */
  2364.  
  2365.   XP_RemoveContextFromList(context);
  2366.  
  2367.   ET_RemoveWindowContext(context, fe_DestroyContext_part2, context);
  2368. }
  2369.  
  2370.  
  2371. /* This is called any time the user performs an action.
  2372.    It reorders the list of contexts so that the most recently
  2373.    used one is at the front.
  2374.  */
  2375. void
  2376. fe_UserActivity (MWContext *context)
  2377. {
  2378.   struct fe_MWContext_cons *rest, *prev;
  2379.  
  2380.   for (prev = 0, rest = fe_all_MWContexts;
  2381.        rest;
  2382.        prev = rest, rest = rest->next)
  2383.     if (rest->context == context)
  2384.       break;
  2385.   if (! rest) abort ();        /* not found?? */
  2386.  
  2387.   /* the new and the last are the same, we're done */
  2388.   if (context == fe_all_MWContexts->context)
  2389.     return;
  2390.  
  2391.   if (context->is_grid_cell) fe_SetGridFocus (context);
  2392.  
  2393.   if (! prev) return;        /* it was already first. */
  2394.  
  2395.   prev->next = rest->next;
  2396.   rest->next = fe_all_MWContexts;
  2397.   fe_all_MWContexts = rest;
  2398. }
  2399.  
  2400.  
  2401. void
  2402. fe_RefreshAllAnchors ()
  2403. {
  2404.   struct fe_MWContext_cons *rest;
  2405.   for (rest = fe_all_MWContexts; rest; rest = rest->next)
  2406.     LO_RefreshAnchors (rest->context);
  2407. }
  2408.  
  2409. /*
  2410.  * XXX Need to make all contexts be deleted through this. - dp
  2411.  */
  2412. void
  2413. fe_delete_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2414. {
  2415.   MWContext *context = (MWContext *) closure;
  2416.  
  2417.   if (fe_WindowCount == 1)
  2418.     {
  2419.       /* Unmap the window right away to give feedback that a delete
  2420.      is in progress. */
  2421.       Widget widget = CONTEXT_WIDGET(context);
  2422.       Window window = (widget ? XtWindow(widget) : 0);
  2423.       if (window)
  2424.     XUnmapWindow (XtDisplay(widget), window);
  2425.  
  2426.       /* Now save files and exit. */
  2427.       fe_Exit (0);
  2428.     }
  2429.   else
  2430.     {
  2431.       if ( someGlobalContext == context )
  2432.       {
  2433.         fe_DestroyContext (context);
  2434.         fe_WindowCount--;
  2435.  
  2436.         someGlobalContext = XP_FindContextOfType(NULL, MWContextBrowser);
  2437.         if (!someGlobalContext)
  2438.               someGlobalContext = XP_FindContextOfType(NULL, MWContextMail);
  2439.         if (!someGlobalContext)
  2440.               someGlobalContext = XP_FindContextOfType(NULL, MWContextNews);
  2441.         if (!someGlobalContext)
  2442.               someGlobalContext = fe_all_MWContexts->context;
  2443.  
  2444.         XmAddWMProtocols(CONTEXT_WIDGET(someGlobalContext), 
  2445.                 &WM_SAVE_YOURSELF,1);
  2446.         XmAddWMProtocolCallback(CONTEXT_WIDGET(someGlobalContext),
  2447.                 WM_SAVE_YOURSELF,
  2448.                 fe_wm_save_self_cb, someGlobalContext);
  2449.      }
  2450.      else
  2451.      {
  2452.         fe_DestroyContext (context);
  2453.         fe_WindowCount--;
  2454.  
  2455.      }
  2456.  
  2457.      if (fe_WindowCount <= 0)
  2458.     abort ();
  2459.     }
  2460. }
  2461.  
  2462. MWContext *
  2463. fe_WidgetToMWContext (Widget widget)
  2464. {
  2465.     struct fe_MWContext_cons* rest;
  2466.     struct fe_MWContext_cons* prev;
  2467.     MWContext* context;
  2468.     Widget transient_for;
  2469.  
  2470.     for (;;) {
  2471.         
  2472.         /*
  2473.          *    Find the toplevel shell.
  2474.          */
  2475.         while (widget != NULL && !XtIsWMShell(widget))
  2476.             widget = XtParent(widget);
  2477.         
  2478.         if (widget == NULL) /* doom */
  2479.             break;
  2480.         
  2481.         /*
  2482.          *    Walk over the list of contexts. For each context,
  2483.          *    get the shell, and compare with the widget's shell.
  2484.          */
  2485.         rest = fe_all_MWContexts;
  2486.         prev = 0;
  2487.         for (; rest != NULL; prev = rest, rest = rest->next) {
  2488.             context = rest->context;
  2489.             if (context != NULL && CONTEXT_DATA(context) != NULL) {
  2490.                 Widget mainw = CONTEXT_WIDGET(context);
  2491.                 Widget parent;
  2492.  
  2493.                 if (mainw == NULL) /* paranoia */
  2494.                     continue;
  2495.  
  2496.                 parent = XtParent(mainw);
  2497.  
  2498.                 /*
  2499.                  *    The old version of this routine allowed
  2500.                  *    for both of these matches, so keep the semantics...
  2501.                  */
  2502.                 if (mainw == widget || parent == widget) { /* match */
  2503.                     /*
  2504.                      *    Push this context to top of list, so this
  2505.                      *    search is faster next time.
  2506.                      */
  2507.                     if (fe_all_MWContexts != rest) {
  2508.                         prev->next = rest->next;
  2509.                         rest->next = fe_all_MWContexts;
  2510.                         fe_all_MWContexts = rest;
  2511.                     }
  2512.                     return context;
  2513.                 }
  2514.             }
  2515.         }
  2516.  
  2517.         /*
  2518.          *    No match. Hmmmm, what if the shell is a transient,
  2519.          *    let's try the shell it's transient for.
  2520.          */
  2521.         if (XtIsSubclass(widget, transientShellWidgetClass)) {
  2522.             XtVaGetValues(widget, XmNtransientFor, &transient_for, 0);
  2523.             widget = transient_for;
  2524.         } else {
  2525.             break;
  2526.         }
  2527.     }
  2528.     
  2529.     /* There is no parent -- hope the caller can deal with a null */
  2530.     return 0;
  2531. }
  2532.  
  2533. /*
  2534.  * Now that we have grids, you can't just walk up to the parent shell
  2535.  * to find the context for a widget.  We are assuming here that the
  2536.  * motion event was always delivered to the drawingarea widget, I hope
  2537.  * that is correct --ejb
  2538.  */
  2539. MWContext *
  2540. fe_MotionWidgetToMWContext (Widget widget)
  2541. {
  2542.   struct fe_MWContext_cons *rest;
  2543.   for (rest = fe_all_MWContexts; rest; rest = rest->next) {
  2544.     if (CONTEXT_DATA (rest->context)->drawing_area == widget)
  2545.       return rest->context;
  2546.   }
  2547.   /* There is no parent -- hope the caller can deal with a null */
  2548.   return 0;
  2549. }
  2550.  
  2551.  
  2552. /* fe_MimimalNoUICleanup
  2553.  *
  2554.  * This does a cleanup of the only the absolute essential stuff.
  2555.  * - saves bookmarks, addressbook
  2556.  * - saves global history
  2557.  * - saves cookies
  2558.  * (since all these saves are protected by flags anyway, we wont endup saving
  2559.  *  again if all these happened before.)
  2560.  * - remove lock file if existent
  2561.  *
  2562.  * This will be called at the following points:
  2563.  * 1. when the x server dies [x_fatal_error_handler()]
  2564.  * 2. when window manages says 'SAVE_YOURSELF'
  2565.  * 3. at_exit_handler()
  2566.  */
  2567. void
  2568. fe_MinimalNoUICleanup()
  2569. {
  2570.   fe_SaveBookmarks ();
  2571.  
  2572.   PREF_SavePrefFile();
  2573.   NR_ShutdownRegistry();
  2574.  
  2575.   RDF_Shutdown();
  2576.   GH_SaveGlobalHistory ();
  2577.   NET_SaveCookies(NULL);
  2578.   AltMailExit();
  2579. }
  2580.  
  2581. /* If there is whitespace at the beginning or end of string, removes it.
  2582.    The string is modified in place.
  2583.  */
  2584. char *
  2585. fe_StringTrim (char *string)
  2586. {
  2587.   char *orig = string;
  2588.   char *new;
  2589.   if (! string) return 0;
  2590.   new = string + strlen (string) - 1;
  2591.   while (new >= string && XP_IS_SPACE (new [0]))
  2592.     *new-- = 0;
  2593.   new = string;
  2594.   while (XP_IS_SPACE (*new))
  2595.     new++;
  2596.   if (new == string)
  2597.     return string;
  2598.   while (*new)
  2599.     *string++ = *new++;
  2600.   *string = 0;
  2601.   return orig;
  2602. }
  2603.  
  2604. /*
  2605.  * fe_StrEndsWith(char *s, char *endstr)
  2606.  *
  2607.  * returns TRUE if string 's' ends with string 'endstr'
  2608.  * else returns FALSE
  2609.  */
  2610. XP_Bool
  2611. fe_StrEndsWith(char *s, char *endstr)
  2612. {
  2613.   int l, lend;
  2614.   XP_Bool retval = FALSE;
  2615.  
  2616.   if (!endstr)
  2617.     /* All strings ends in NULL */
  2618.     return(TRUE);
  2619.   if (!s)
  2620.     /* NULL strings will never have endstr at its end */
  2621.     return(FALSE);
  2622.  
  2623.   lend = strlen(endstr);
  2624.   l = strlen(s);
  2625.   if (l >= lend && !strcmp(s+l-lend, endstr))
  2626.     retval = TRUE;
  2627.   return (retval);
  2628. }
  2629.  
  2630. char *
  2631. fe_Basename (const char *s)
  2632. {
  2633.     int len;
  2634.     char *p;
  2635.  
  2636.     if (!s) return (s);
  2637.     len = strlen(s);
  2638.     p = &s[len-1];
  2639.     
  2640.     while(--len > 0 && *p != '/') p--;
  2641.     if (*p == '/') p++;
  2642.     return (p);
  2643. }
  2644.  
  2645.  
  2646. /* Mail stuff */
  2647.  
  2648. const char *
  2649. FE_UsersMailAddress (void)
  2650. {
  2651.   static char *cached_uid = 0;
  2652.   char *uid, *name;
  2653.   if (fe_globalPrefs.email_address && *fe_globalPrefs.email_address)
  2654.     {
  2655.       if (cached_uid) free (cached_uid);
  2656.       cached_uid = 0;
  2657.       return fe_globalPrefs.email_address;
  2658.     }
  2659.   else if (cached_uid)
  2660.     {
  2661.       return cached_uid;
  2662.     }
  2663.   else
  2664.     {
  2665.       fe_DefaultUserInfo (&uid, &name, False);
  2666.       free (name);
  2667.       cached_uid = uid;
  2668.       return uid;
  2669.     }
  2670. }
  2671.  
  2672.  
  2673. const char *
  2674. FE_UsersRealMailAddress (void)
  2675. {
  2676.   static char *cached_uid = 0;
  2677.   if (cached_uid)
  2678.     {
  2679.       return cached_uid;
  2680.     }
  2681.   else
  2682.     {
  2683.       char *uid, *name;
  2684.       fe_DefaultUserInfo (&uid, &name, True);
  2685.       free (name);
  2686.       cached_uid = uid;
  2687.       return uid;
  2688.     }
  2689. }
  2690.  
  2691.  
  2692. const char *
  2693. FE_UsersFullName (void)
  2694. {
  2695.   static char *cached_name = 0;
  2696.   char *uid, *name;
  2697.   if (fe_globalPrefs.real_name && *fe_globalPrefs.real_name)
  2698.     {
  2699.       if (cached_name) free (cached_name);
  2700.       cached_name = 0;
  2701.       return fe_globalPrefs.real_name;
  2702.     }
  2703.   else if (cached_name)
  2704.     {
  2705.       return cached_name;
  2706.     }
  2707.   else
  2708.     {
  2709.       fe_DefaultUserInfo (&uid, &name, False);
  2710.       free (uid);
  2711.       cached_name = name;
  2712.       return name;
  2713.     }
  2714. }
  2715.  
  2716.  
  2717. const char *
  2718. FE_UsersOrganization (void)
  2719. {
  2720.   static char *cached_org = 0;
  2721.   if (cached_org)
  2722.     free (cached_org);
  2723.   cached_org = strdup (fe_globalPrefs.organization
  2724.                ? fe_globalPrefs.organization
  2725.                : "");
  2726.   return cached_org;
  2727. }
  2728.  
  2729. #ifdef MOZ_MAIL_NEWS
  2730. const char *
  2731. FE_UsersSignature (void)
  2732. {
  2733.   static char *signature = NULL;
  2734.   XP_File file;
  2735.   time_t sig_date = 0;
  2736.     
  2737.   if (signature)
  2738.     XP_FREE (signature);
  2739.         
  2740.   file = XP_FileOpen (fe_globalPrefs.signature_file,
  2741.               xpSignature, XP_FILE_READ);
  2742.     
  2743.   if (file)
  2744.     {
  2745.       struct stat st;
  2746.       char buf [1024];
  2747.       char *s = buf;
  2748.     
  2749.       int left = sizeof (buf) - 2;
  2750.       int size;
  2751.       *s = 0;
  2752.  
  2753.       if (!fstat (fileno (file), &st))
  2754.     sig_date = st.st_mtime;
  2755.  
  2756.       while ((size = XP_FileRead (s, left, file)) && left > 0)
  2757.     {
  2758.       left -= size;
  2759.       s += size;
  2760.     }
  2761.  
  2762.       *s = 0;
  2763.  
  2764.       /* take off all trailing whitespace */
  2765.       s--;
  2766.       while (s >= buf && isspace (*s))
  2767.     *s-- = 0;
  2768.       /* terminate with a single newline. */
  2769.       s++;
  2770.       *s++ = '\n';
  2771.       *s++ = 0;
  2772.       XP_FileClose (file);
  2773.       if ( !strcmp (buf, "\n"))
  2774.     signature = NULL;
  2775.       else
  2776.     signature = strdup (buf);
  2777.     }
  2778.   else
  2779.     signature = NULL;
  2780.  
  2781.   /* The signature file date has changed - check the contents of the file
  2782.      again, and save that date to the preferences file so that it is checked
  2783.      only when the file changes, even if Netscape has been restarted in the
  2784.      meantime. */
  2785.   if (fe_globalPrefs.signature_date != sig_date)
  2786.     {
  2787.       MWContext *context =
  2788.     XP_FindContextOfType(0, MWContextMessageComposition);
  2789.       if (!context) context = fe_all_MWContexts->context;
  2790.       MISC_ValidateSignature (context, signature);
  2791.       fe_globalPrefs.signature_date = sig_date;
  2792.  
  2793.       if (!XFE_SavePrefs ((char *) fe_globalData.user_prefs_file,
  2794.               &fe_globalPrefs))
  2795.     fe_perror (context, XP_GetString( XFE_ERROR_SAVING_OPTIONS ) );
  2796.     }
  2797.  
  2798.   return signature;
  2799. }
  2800. #endif  /* MOZ_MAIL_NEWS */
  2801.  
  2802.  
  2803. int32
  2804. FE_GetContextID (MWContext * window_id)
  2805. {
  2806.    return((int32) window_id);
  2807. }
  2808.  
  2809. XP_Bool
  2810. XFE_UseFancyFTP (MWContext *context)
  2811. {
  2812.   return CONTEXT_DATA (context)->fancy_ftp_p;
  2813. }
  2814.  
  2815. XP_Bool
  2816. XFE_UseFancyNewsgroupListing (MWContext * window_id)
  2817. {
  2818.   return False;
  2819. }
  2820.  
  2821. /* FE_ShowAllNewsArticles
  2822.  *
  2823.  * Return true if the user wants to see all newsgroup  
  2824.  * articles and not have the number restricted by
  2825.  * .newsrc entries
  2826.  */
  2827. XP_Bool
  2828. XFE_ShowAllNewsArticles (MWContext *window_id)
  2829. {
  2830.     return(FALSE);  /* temporary LJM */
  2831. }
  2832.  
  2833. int 
  2834. XFE_FileSortMethod (MWContext * window_id)
  2835. {
  2836.    return (SORT_BY_NAME);
  2837. }
  2838.  
  2839. int16
  2840. INTL_DefaultDocCharSetID(MWContext *cxt)
  2841. {
  2842.     int16    csid;
  2843.  
  2844.     if (cxt)
  2845.     {
  2846.         INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cxt);
  2847.         if (INTL_GetCSIDocCSID(csi))      
  2848.         {
  2849.             csid = INTL_GetCSIDocCSID(csi);
  2850.         }
  2851.         else if (cxt->fe.data && cxt->fe.data->xfe_doc_csid)
  2852.         {
  2853.             csid = cxt->fe.data->xfe_doc_csid;
  2854.         }
  2855.         else
  2856.         {
  2857.             csid = fe_globalPrefs.doc_csid;
  2858.         }
  2859.     }
  2860.     else
  2861.     {
  2862.         csid = fe_globalPrefs.doc_csid;
  2863.     }
  2864.  
  2865.     return csid;
  2866. }
  2867.  
  2868. char *
  2869. INTL_ResourceCharSet(void)
  2870. {
  2871.     return fe_LocaleCharSetName;
  2872. }
  2873.  
  2874. void
  2875. INTL_Relayout(MWContext *pContext)
  2876. {
  2877.   if(XP_IsContextBusy(pContext) == FALSE)
  2878.     {
  2879.       fe_ReLayout(pContext, NET_DONT_RELOAD);
  2880.     }
  2881. }
  2882.  
  2883.  
  2884.  
  2885. typedef struct fe_timeout {
  2886.   TimeoutCallbackFunction func;
  2887.   void* closure;
  2888.   XtIntervalId timer;
  2889.   uint32 serial_num;
  2890.   struct fe_timeout *next;
  2891. } fe_timeout;
  2892.  
  2893. static uint32 fe_timeout_serial_num = 0; /* Unique token for each timeout */
  2894. static fe_timeout *fe_TimeoutList = NULL;
  2895.  
  2896. static Bool
  2897. remove_timeout_from_list(uint32 serial_num, Bool clear_timeout)
  2898. {
  2899.   fe_timeout **p, *t;
  2900.  
  2901.   p = &fe_TimeoutList;
  2902.   while ((t = *p)) {
  2903.       if (t->serial_num == serial_num) {
  2904.           *p = t->next;
  2905.           if (clear_timeout)
  2906.               XtRemoveTimeOut(t->timer);
  2907.           XP_FREE(t);
  2908.           return TRUE;
  2909.       }
  2910.       p = &t->next;
  2911.   }
  2912.   return FALSE;
  2913. }
  2914.  
  2915. static void
  2916. fe_do_timeout(XtPointer p, XtIntervalId* id)
  2917. {
  2918.   fe_timeout* timer = (fe_timeout*) p;
  2919.   XP_ASSERT(timer->timer == *id);
  2920.   (*timer->func)(timer->closure);
  2921.   if (!remove_timeout_from_list(timer->serial_num, FALSE)) {
  2922.       XP_ASSERT(0);
  2923.   }
  2924. }
  2925.  
  2926. void* 
  2927. FE_SetTimeout(TimeoutCallbackFunction func, void* closure, uint32 msecs)
  2928. {
  2929.   fe_timeout* timer;
  2930.   timer = XP_NEW(fe_timeout);
  2931.   if (!timer) return NULL;
  2932.   timer->func = func;
  2933.   timer->closure = closure;
  2934.   timer->timer = XtAppAddTimeOut(fe_XtAppContext, msecs, fe_do_timeout, timer);
  2935.   timer->serial_num = ++fe_timeout_serial_num;
  2936.   timer->next = fe_TimeoutList;
  2937.   fe_TimeoutList = timer;
  2938.   return (void*)fe_timeout_serial_num;
  2939. }
  2940.  
  2941. void 
  2942. FE_ClearTimeout(void* timer_id)
  2943. {
  2944.   remove_timeout_from_list((uint32)timer_id, TRUE);
  2945. }
  2946.  
  2947. char *
  2948. FE_GetCipherPrefs(void)
  2949. {
  2950.     if (fe_globalPrefs.cipher == NULL)
  2951.     return NULL;
  2952.     return(strdup(fe_globalPrefs.cipher));
  2953. }
  2954.  
  2955. void
  2956. FE_SetCipherPrefs(MWContext *context, char *cipher)
  2957. {
  2958.   if (fe_globalPrefs.cipher) {
  2959.     if (!strcmp(fe_globalPrefs.cipher, cipher))
  2960.       return;
  2961.     XP_FREE(fe_globalPrefs.cipher);
  2962.   }
  2963.   fe_globalPrefs.cipher = strdup(cipher);
  2964.   if (!XFE_SavePrefs ((char *) fe_globalData.user_prefs_file, &fe_globalPrefs))
  2965.   {
  2966.       if (context == NULL) {
  2967.       MWContext *someContext;
  2968.       /* Type to find a context */
  2969.       someContext = XP_FindContextOfType(NULL, MWContextBrowser);
  2970.       if (!someContext)
  2971.           someContext = XP_FindContextOfType(NULL, MWContextMail);
  2972.       if (!someContext)
  2973.           someContext = XP_FindContextOfType(NULL, MWContextNews);
  2974.       if (!someContext)
  2975.           someContext = fe_all_MWContexts->context;
  2976.       context = someContext;
  2977.       }
  2978.       if (context != NULL)
  2979.       fe_perror (context, XP_GetString( XFE_ERROR_SAVING_OPTIONS));
  2980.   }
  2981. }
  2982.  
  2983.  
  2984. /************************
  2985.  * File status routines *
  2986.  ************************/
  2987. /*
  2988.  * File changes since last seen.
  2989.  * For error case of file not present, it returns FALSE and doesn't change
  2990.  *    return value new_mtime.
  2991.  * If file has changed, returns TRUE and new_mtime if not null is updated
  2992.  *    to the new modified time.
  2993.  * If file has not changed, return FALSE and doesn't change new_mtime.
  2994.  */
  2995. XP_Bool
  2996. fe_isFileChanged(char *name, time_t mtime, time_t *new_mtime)
  2997. {
  2998.     XP_StatStruct st;
  2999.     XP_Bool ret = FALSE;
  3000.     
  3001.     if (name && *name && !stat(name, &st))
  3002.       if (st.st_mtime != mtime) ret = TRUE;
  3003.  
  3004.     if (ret && new_mtime)
  3005.       *new_mtime = st.st_mtime;
  3006.  
  3007.     return (ret);
  3008. }
  3009.  
  3010. /*
  3011.  * File exists
  3012.  */
  3013. Boolean
  3014. fe_isFileExist(char *name)
  3015. {
  3016.     XP_StatStruct st;
  3017.     if (!name || !*name) return (False);
  3018.     if (!stat (name, &st))
  3019.     return (True);
  3020.     else
  3021.     return (False);
  3022. }
  3023.  
  3024. /*
  3025.  * File exists and is readable.
  3026.  */
  3027. Boolean
  3028. fe_isFileReadable(char *name)
  3029. {
  3030.     FILE *fp;
  3031.     if (!name || !*name) return (False);
  3032.     fp = fopen(name, "r");
  3033.     if (fp) {
  3034.     fclose(fp);
  3035.     return (True);
  3036.     }
  3037.     else
  3038.     return (False);
  3039. }
  3040.  
  3041. /*
  3042.  * File is a directory
  3043.  */
  3044. Boolean
  3045. fe_isDir(char *name)
  3046. {
  3047.     XP_StatStruct st;
  3048.     if (!name || !*name) return (False);
  3049.     if (!stat (name, &st) && S_ISDIR(st.st_mode))
  3050.     return (True);
  3051.     else
  3052.     return (False);
  3053. }
  3054.  
  3055.  
  3056. /*
  3057.  * Layering support.  LO_RefreshArea is called through compositor.
  3058.  */
  3059.  
  3060. void
  3061. fe_RefreshArea(MWContext *context, int32 x, int32 y,
  3062.                 uint32 width, uint32 height)
  3063. {
  3064.     if(context->compositor)
  3065.         {
  3066.             XP_Rect rect;
  3067.             
  3068.             rect.left = x;
  3069.             rect.top = y;
  3070.             rect.right = x + width;
  3071.             rect.bottom = y + height;
  3072.             CL_UpdateDocumentRect((context)->compositor, &rect, PR_TRUE);
  3073.         }
  3074. #ifdef EDITOR
  3075.     if (EDT_IS_EDITOR(context))
  3076.         fe_EditorRefreshArea(context, x, y, width, height);
  3077. #endif /*EDITOR*/
  3078. }
  3079.  
  3080. void
  3081. fe_RefreshAreaRequest(MWContext *context, int32 x, int32 y,
  3082.                       uint32 width, uint32 height)
  3083. {
  3084.     if(context->compositor) {
  3085.         XP_Rect rect;
  3086.             
  3087.         rect.left = x;
  3088.         rect.top = y;
  3089.         rect.right = x + width;
  3090.         rect.bottom = y + height;
  3091.         CL_UpdateDocumentRect((context)->compositor, &rect, PR_FALSE);
  3092.     }
  3093. }
  3094.  
  3095. extern void fe_HTMLViewDoPopup (MWContext *context, CL_Layer *layer,
  3096.                                 CL_Event *layer_event);
  3097. extern void fe_HTMLDragSetLayer(CL_Layer *layer);
  3098.  
  3099. /* Handle events on a layer-specific basis. */
  3100. PRBool FE_HandleLayerEvent(MWContext *context, CL_Layer *layer,
  3101.                            CL_Event *layer_event)
  3102. {
  3103.     PRBool handled_event_p = TRUE;
  3104.     Boolean synthesized_event_p = FALSE;
  3105.     fe_EventStruct *fe_event = (fe_EventStruct *)layer_event->fe_event;
  3106.     XEvent *event = NULL;
  3107.     fe_MouseActionEnum mouse_action = FE_INVALID_MOUSE_ACTION;
  3108.  
  3109.     if (fe_event)
  3110.         {
  3111.             mouse_action = fe_event->mouse_action;
  3112.         }
  3113.     else
  3114.         {
  3115.             /* This means that we have a synthesized event, so fill
  3116.                in the FE part. */
  3117.  
  3118.             int32 layer_x_offset, layer_y_offset;
  3119.  
  3120.             synthesized_event_p = TRUE;
  3121.             fe_event = XP_NEW_ZAP(fe_EventStruct);
  3122.             XP_ASSERT(fe_event);
  3123.  
  3124.             /* Create an XEvent. */
  3125.             event = XP_NEW_ZAP(XEvent);
  3126.             XP_ASSERT(event);
  3127.  
  3128.             layer_x_offset = CL_GetLayerXOffset(layer);
  3129.             layer_y_offset = CL_GetLayerYOffset(layer);
  3130.  
  3131.             /* XXX This part of the event synthesis code is currently based
  3132.                on the mouse bindings specified in the default resource file.
  3133.                We need to eventually change it so that it will work with any
  3134.                set of mouse bindings that the user specifies. */
  3135.  
  3136.             switch (layer_event->type)
  3137.                 {
  3138.                 case CL_EVENT_MOUSE_BUTTON_DOWN:
  3139.                     event->type = ButtonPress;
  3140.                     event->xbutton.x = layer_event->x + layer_x_offset -
  3141.                         CONTEXT_DATA (context)->document_x;
  3142.                     event->xbutton.y = layer_event->y + layer_y_offset -
  3143.                         CONTEXT_DATA (context)->document_y;
  3144.                     event->xbutton.time =
  3145.                         XtLastTimestampProcessed(XtDisplay(CONTEXT_WIDGET(context)));
  3146.                     
  3147.                     switch (layer_event->which)
  3148.                         {
  3149.                         case 1: /* Left mouse. */
  3150.                             event->xbutton.button = 1;
  3151.                             mouse_action = FE_ARM_LINK;
  3152.                             break;
  3153.  
  3154.                         case 2: /* Right mouse. */
  3155.                             event->xbutton.button = 3;
  3156.                             mouse_action = FE_POPUP_MENU;
  3157.                             break;
  3158.  
  3159.                         default:
  3160.                             XP_ASSERT(0);
  3161.                             break;
  3162.                         }
  3163.                     break;
  3164.  
  3165.                 case CL_EVENT_MOUSE_BUTTON_UP:
  3166.                     event->type = ButtonRelease;
  3167.                     event->xbutton.x = layer_event->x + layer_x_offset -
  3168.                         CONTEXT_DATA (context)->document_x;
  3169.                     event->xbutton.y = layer_event->y + layer_y_offset -
  3170.                         CONTEXT_DATA (context)->document_y;
  3171.                     event->xbutton.time =
  3172.                         XtLastTimestampProcessed(XtDisplay(CONTEXT_WIDGET(context)));
  3173.                     
  3174.                     switch (layer_event->which)
  3175.                         {
  3176.                         case 1: /* Left mouse. */
  3177.                             event->xbutton.button = 1;
  3178.                             mouse_action = FE_ACTIVATE_LINK;
  3179.                             break;
  3180.  
  3181.                         default:
  3182.                             XP_ASSERT(0);
  3183.                             break;
  3184.                         }
  3185.                     break;
  3186.                     
  3187.                 case CL_EVENT_MOUSE_MOVE:
  3188.                     event->type = MotionNotify;
  3189.                     event->xmotion.x = layer_event->x + layer_x_offset -
  3190.                         CONTEXT_DATA (context)->document_x;
  3191.                     event->xmotion.y = layer_event->y + layer_y_offset -
  3192.                         CONTEXT_DATA (context)->document_y;
  3193.                     event->xmotion.time =
  3194.                         XtLastTimestampProcessed(XtDisplay(CONTEXT_WIDGET(context)));
  3195.                     
  3196.                     switch (layer_event->which)
  3197.                         {
  3198.                         case 0: /* No button. */
  3199.                             mouse_action = FE_DESCRIBE_LINK; 
  3200.                             break;
  3201.                             
  3202.                         case 1: /* Left mouse. */
  3203.                             event->xmotion.state = Button1Mask;
  3204.                             mouse_action = FE_DISARM_LINK_IF_MOVED;
  3205.                             break;
  3206.  
  3207.                         case 2: /* Right mouse. */
  3208.                             event->xmotion.state = Button3Mask;
  3209.                             mouse_action = FE_DISARM_LINK_IF_MOVED;
  3210.                             break;
  3211.  
  3212.                         default:
  3213.                             XP_ASSERT(0);
  3214.                             break;
  3215.                         }
  3216.                     break;
  3217.  
  3218.         case CL_EVENT_MOUSE_ENTER:
  3219.         case CL_EVENT_MOUSE_LEAVE:
  3220.         case CL_EVENT_KEY_FOCUS_GAINED:
  3221.         case CL_EVENT_KEY_FOCUS_LOST:
  3222.             if (synthesized_event_p) {
  3223.                 XP_FREE(event);
  3224.             XP_FREE(fe_event);
  3225.             }
  3226.           return FALSE;
  3227.  
  3228.                 default:
  3229.                     XP_ASSERT(0);
  3230.                     break;
  3231.                 }
  3232.  
  3233. #ifdef LAYERS_FULL_FE_EVENT
  3234.             fe_event->event = event;
  3235.             fe_event->av = NULL;
  3236.             fe_event->ac = NULL;
  3237.             fe_event->mouse_action = mouse_action;
  3238. #else
  3239.         fe_event_stuff(context,fe_event,event,0,0,mouse_action);
  3240. #endif
  3241.             
  3242.             layer_event->fe_event = fe_event;
  3243.  
  3244.         }
  3245.     
  3246.     switch (mouse_action)
  3247.         {
  3248.             /* These correspond to 
  3249.                layer_event->type = CL_EVENT_MOUSE_BUTTON_DOWN */
  3250.  
  3251.         case FE_ARM_LINK:
  3252.             /* hack to allow Motif drag and drop to catch Layer event. */
  3253.             fe_HTMLDragSetLayer(layer);
  3254.             
  3255.             fe_arm_link_action_for_layer(context, layer, layer_event);
  3256.             break;
  3257.                     
  3258.         case FE_EXTEND_SELECTION:
  3259.             fe_extend_selection_action_for_layer(context, layer,
  3260.                                                  layer_event);
  3261.             break;
  3262.  
  3263.         case FE_POPUP_MENU:
  3264.         fe_HTMLViewDoPopup (context, layer, layer_event);
  3265.             break;
  3266.  
  3267.             /* These correspond to
  3268.                layer_event->type = CL_EVENT_MOUSE_BUTTON_UP */
  3269.  
  3270.         case FE_ACTIVATE_LINK:
  3271.             fe_activate_link_action_for_layer(context, layer,
  3272.                                               layer_event);
  3273.             break;
  3274.  
  3275.         case FE_DISARM_LINK:
  3276. #ifdef LAYERS_SEPARATE_DISARM
  3277.             fe_disarm_link_action_for_layer(context, layer,
  3278.                                             layer_event);
  3279. #else
  3280. #ifdef DEBUG
  3281.         printf("FE_HandleLayerEvent(): unexpected FE_DISARM_LINK\n");
  3282. #endif
  3283. #endif
  3284.             break;
  3285.  
  3286.             /* These correspond to
  3287.                layer_event->type = CL_EVENT_MOUSE_MOVE */
  3288.  
  3289.         case FE_DESCRIBE_LINK:
  3290.             fe_describe_link_action_for_layer(context, layer,
  3291.                                               layer_event);
  3292.             break;
  3293.                     
  3294.         case FE_DISARM_LINK_IF_MOVED:
  3295.             fe_disarm_link_if_moved_action_for_layer(context, layer,
  3296.                                                      layer_event);
  3297.             break;
  3298.             
  3299.             /* No actions corresponding to
  3300.                layer_event->type = CL_EVENT_MOUSE_BUTTON_MULTI_CLICK */
  3301.  
  3302.       case FE_KEY_UP:
  3303.         fe_key_up_in_text_action_for_layer(context, layer,
  3304.                            layer_event);
  3305.         break;
  3306.             
  3307.       case FE_KEY_DOWN:
  3308.         fe_key_down_in_text_action_for_layer(context, layer,
  3309.                          layer_event);
  3310.         break;
  3311.             
  3312.         default:
  3313.             XP_ASSERT(0);
  3314.             break;
  3315.         }
  3316.  
  3317.     if (synthesized_event_p)
  3318.         {
  3319.             if (mouse_action == FE_ACTIVATE_LINK)
  3320.           {
  3321.         /* disarm is now triggered by activate, instead of
  3322.          *  by the mouseclick, so calling 
  3323.          *  fe_activate_link_action_for_layer() above triggered
  3324.          *  the disarm already. -- francis
  3325.          */
  3326. #ifdef LAYERS_SEPARATE_DISARM
  3327.         fe_disarm_link_action_for_layer(context, layer,
  3328.                         layer_event);
  3329. #endif
  3330.           }
  3331.             XP_FREE(event);
  3332.             XP_FREE(fe_event);
  3333.         }
  3334.  
  3335.     return handled_event_p;
  3336. }
  3337.  
  3338. /* XXX - For now, unix does not have windowless plugins */
  3339. PRBool FE_HandleEmbedEvent(MWContext *context, LO_EmbedStruct *embed,
  3340.                            CL_Event *event)
  3341. {
  3342.   return PR_FALSE;
  3343. }
  3344.  
  3345.  
  3346. /* the purpose of the following code is to provide the backend
  3347.  * a way to get temp files associated with each ldap server.
  3348.  * these files should have unique names, meaning for each different
  3349.  * ldap server, a different file is used. at the same time, if the
  3350.  * backend queries with the same ldap server, the same file name should
  3351.  * be returned (because we want to allow user to continue from previous
  3352.  * searches) 
  3353.  * 
  3354.  * anything with ifdef _XP_TMP_FILENAME_FOR_LDAP_ in it needs to be
  3355.  * implemented. right now we are just returning hardcoded names to test
  3356.  * the ldap features.
  3357.  */
  3358.  
  3359. /*
  3360. #define _XP_TMP_FILENAME_FOR_LDAP_
  3361. */
  3362.  
  3363. char* fe_GetLDAPTmpFile(char *name) {
  3364.     char* home = getenv("HOME");
  3365.     static char tmp[1024];
  3366.     if (!home) home = "";
  3367.     if (!name) return NULL;
  3368.  
  3369.     sprintf(tmp, "%.900s/.netscape/", home);
  3370.  
  3371. #ifdef _XP_TMP_FILENAME_FOR_LDAP_
  3372.     /* we need to write this */
  3373.     /* what we need: look for the temp name associated with the
  3374.      * ldap server specified in the array "name".
  3375.      * if we find it, we return it, if not, we create 
  3376.      * a new tmp file name and "remember" that it is associated
  3377.      * with this particular ldap server - benjie */
  3378.  
  3379.     /* here we look for it */
  3380.  
  3381.     if (HA_I_FOUND_IT) {
  3382.         return THE_FILE_NAME;
  3383.     } else {
  3384.         /* we create a new one */
  3385.         char *ldapfile=NULL;
  3386.         strcat(tmp,"ldapXXXXXX");
  3387.         ldapfile = mktemp(tmp);
  3388.         if (!ldapfile) return null;
  3389.         else {
  3390.             PR_snprintf(tmp, sizeof (tmp),"%s.nab",ldapfile);
  3391.             /ok, now we save the temp file name*/
  3392.  
  3393.             /* saving temp file name associated with the ldap server here */
  3394.  
  3395.             return tmp;
  3396.         }
  3397.      }
  3398.     return NULL;
  3399. #else
  3400.     if (strcmp(name,"scrappy")==0) {
  3401.         strcat(tmp,"nsldap.nab\0");
  3402.         return tmp;
  3403.     } else if (strcmp(name,"umich")==0) {
  3404.         strcat(tmp,"umich.nab\0");
  3405.         return tmp;
  3406.     } else return NULL;
  3407. #endif
  3408. }
  3409.  
  3410.  
  3411. /* this should be called from the backend (XP_FileName) */
  3412. /* for now it is only be called from fe */
  3413. char* FE_GetFileName(char *name, XP_FileType type) {
  3414.     switch(type) {
  3415.         case xpAddrBook:
  3416.             return fe_GetLDAPTmpFile(name);
  3417.         default:
  3418.             return NULL;
  3419.     }
  3420. }
  3421.  
  3422. /*
  3423.  *    Walks over a tree, calling mappee callback on each widget.
  3424.  */
  3425. XtPointer
  3426. fe_WidgetTreeWalk(Widget widget, fe_WidgetTreeWalkMappee callback,
  3427.           XtPointer data)
  3428. {
  3429.   Arg       av[8];
  3430.   Cardinal  ac;
  3431.   Widget*   children;
  3432.   Cardinal  nchildren;
  3433.   Cardinal  i;
  3434.   XtPointer rv;
  3435.  
  3436.   if (widget == NULL || callback == NULL)
  3437.       return 0;
  3438.  
  3439.   if (XtIsSubclass(widget, compositeWidgetClass)) {
  3440.  
  3441.       ac = 0;
  3442.       XtSetArg(av[ac], XmNchildren, &children); ac++;
  3443.       XtSetArg(av[ac], XmNnumChildren, &nchildren); ac++;
  3444.       XtGetValues(widget, av, ac);
  3445.       
  3446.       for (i = 0; i < nchildren; i++) {
  3447.       rv = fe_WidgetTreeWalk(children[i], callback, data);
  3448.       if (rv != 0)
  3449.           return rv;
  3450.       }
  3451.   }
  3452.  
  3453.   return (callback)(widget, data);
  3454. }
  3455.  
  3456. /*
  3457.  * fe_WidgetTreeWalkChildren
  3458.  *
  3459.  * Intension here is to call the mappee callback for all children in the
  3460.  * tree taking into account the cascade menus.
  3461.  */
  3462. XtPointer
  3463. fe_WidgetTreeWalkChildren(Widget widget, fe_WidgetTreeWalkMappee callback,
  3464.               XtPointer closure)
  3465. {
  3466.   Widget *buttons = 0, menu = 0;
  3467.   Cardinal nbuttons = 0;
  3468.   int i;
  3469.   XtPointer ret = 0;
  3470.   XtVaGetValues (widget, XmNchildren, &buttons, XmNnumChildren, &nbuttons, 0);
  3471.   for (i = 0; ret == 0 && i < nbuttons; i++)
  3472.     {
  3473.       Widget item = buttons[i];
  3474.       if (XmIsToggleButton(item) || XmIsToggleButtonGadget(item) ||
  3475.           XmIsPushButton(item) || XmIsPushButtonGadget(item) ||
  3476.           XmIsCascadeButton(item) || XmIsCascadeButtonGadget(item))
  3477.     ret = (callback) (item, closure);
  3478.       if (ret != 0) break;
  3479.       if (XmIsCascadeButton(item) || XmIsCascadeButtonGadget(item)) {
  3480.     XtVaGetValues (item, XmNsubMenuId, &menu, 0);
  3481.     if (menu)
  3482.       ret = fe_WidgetTreeWalkChildren(menu, callback, closure);
  3483.       }
  3484.     }
  3485.   return(ret);
  3486. }
  3487.  
  3488.  
  3489. static XtPointer
  3490. fe_find_widget_mappee(Widget widget, XtPointer data)
  3491. {
  3492.     char* match_name = (char*)data;
  3493.     char* name = XtName(widget);
  3494.  
  3495.     if (strcmp(name, match_name) == 0) {
  3496.     return (XtPointer) widget; /* non-zero, will force termination of walk */
  3497.     } else {
  3498.     return 0;
  3499.     }
  3500. }
  3501.  
  3502. Widget
  3503. fe_FindWidget(Widget top, char* name)
  3504. {
  3505.     XtPointer rv;
  3506.  
  3507.     rv = fe_WidgetTreeWalk(top, fe_find_widget_mappee, (XtPointer)name);
  3508.     
  3509.     return (Widget)rv;
  3510. }
  3511.  
  3512. /*
  3513.  *    Tool tips.
  3514.  */
  3515. static Widget       fe_tool_tips_widget;   /* current hot widget */
  3516. static XtIntervalId fe_tool_tips_timer_id; /* timer id for non-movement */
  3517. static Widget       fe_tool_tips_shell;    /* posted tips shell */
  3518.  
  3519. /*
  3520.  *    New tool tip code.
  3521.  */
  3522. typedef struct TipInfo {
  3523.     struct TipInfo* m_next;
  3524.     XtPointer       m_key;
  3525.     union {
  3526.         /* if callback == GADGET_DUMMY, gadgets is valid */
  3527.         XtCallbackRec   callback_rec;
  3528.         struct TipInfo* gadgets;
  3529.     } u;
  3530.     int     x, y; /* mouse pos */
  3531.     XP_Bool rePosition; 
  3532. } TipInfo;
  3533.  
  3534. #define m_gadgets  u.gadgets
  3535. #define m_callback u.callback_rec.callback
  3536. #define m_closure  u.callback_rec.closure
  3537.  
  3538. static TipInfo*
  3539. TipInfoNew(XtPointer key, XtCallbackProc callback, XtPointer closure)
  3540. {
  3541.     TipInfo* info;
  3542.  
  3543.     info = XP_NEW(TipInfo);
  3544.  
  3545.     info->m_key = key;
  3546.     info->m_callback = callback;
  3547.     info->m_closure = closure;
  3548.     info->m_next = NULL;
  3549.     info->x = -10;
  3550.     info->y = -10;
  3551.     info->rePosition = False;
  3552.     return info;
  3553. }
  3554.  
  3555. static void
  3556. TipInfoDelete(TipInfo* info)
  3557. {
  3558.     XP_FREE(info);
  3559. }
  3560.  
  3561. static TipInfo*
  3562. TipInfoListInsert(TipInfo** list, TipInfo* info)
  3563. {
  3564.     info->m_next = *list;
  3565.     *list = info;
  3566.  
  3567.     return info;
  3568. }
  3569.  
  3570. static void
  3571. TipInfoListDelete(TipInfo* info)
  3572. {
  3573.     TipInfo* next;
  3574.     while (info != NULL) {
  3575.         next = info->m_next;
  3576.         XP_FREE(info);
  3577.         info = next;
  3578.     }
  3579. }
  3580.  
  3581. static TipInfo*
  3582. TipInfoListFind(TipInfo* head, XtPointer key)
  3583. {
  3584.     TipInfo* foo;
  3585.  
  3586.     for (foo = head; foo != NULL; foo = foo->m_next) {
  3587.         if (foo->m_key == key)
  3588.             break;
  3589.     }
  3590.  
  3591.     return foo;
  3592. }
  3593.  
  3594. static TipInfo*
  3595. TipInfoListRemove(TipInfo** list, XtPointer key)
  3596. {
  3597.     TipInfo* info = *list;
  3598.     TipInfo* prev = NULL;
  3599.  
  3600.     for (; info != NULL; prev = info, info = info->m_next) {
  3601.         if (info->m_key == key) {
  3602.             if (prev != NULL) {
  3603.                 prev->m_next = info->m_next;
  3604.             } else {
  3605.                 *list = info->m_next;
  3606.             }
  3607.             TipInfoDelete(info);
  3608.             break;
  3609.         }
  3610.     }
  3611.  
  3612.     return *list;
  3613. }
  3614.  
  3615. static TipInfo* tips_manager_list;
  3616. #ifdef USE_TIP_WIDGET_LIST
  3617. static TipInfo* tips_widget_list;
  3618. #endif
  3619.  
  3620. static void
  3621. tip_dummy_manager_cb(Widget widget, XtPointer closure, XtPointer cb) {}
  3622.  
  3623. #define TIPINFO_IS_MANAGER(i) ((i)->m_callback == tip_dummy_manager_cb)
  3624.  
  3625. /*
  3626.  *    When there is no callback info, there is no need to allocate
  3627.  *    memory to save it. Use this as a dummy callback info.
  3628.  */
  3629. static TipInfo tips_no_callback_info; /* must be 0s */
  3630.  
  3631. static void
  3632. tips_widget_death_cb(Widget widget, XtPointer closure, XtPointer cb)
  3633. {
  3634.     TipInfo* info = (TipInfo*)closure;
  3635.  
  3636.     XtRemoveCallback(widget, XmNdestroyCallback, tips_widget_death_cb, info);
  3637.     if (TIPINFO_IS_MANAGER(info)) {
  3638.         TipInfoListDelete(info->m_gadgets);
  3639.         TipInfoListRemove(&tips_manager_list, (XtPointer)info);
  3640.     }
  3641. #ifdef USE_TIP_WIDGET_LIST
  3642.     else
  3643.     {
  3644.         TipInfoListRemove(&tips_widget_list, info);
  3645.     }
  3646. #endif
  3647.     if (info != &tips_no_callback_info)
  3648.         TipInfoDelete(info);
  3649.  
  3650.     if (fe_tool_tips_widget ==  widget)
  3651.         fe_tool_tips_widget = NULL;
  3652. }
  3653.  
  3654. static TipInfo*
  3655. TipInfoNewManager(Widget manager)
  3656. {
  3657.     TipInfo* info =  TipInfoNew((XtPointer)manager, tip_dummy_manager_cb, NULL);
  3658.  
  3659.     XtAddCallback(manager, XmNdestroyCallback, tips_widget_death_cb, info);
  3660.  
  3661.     return info;
  3662. }
  3663.  
  3664. static TipInfo*
  3665. TipInfoNewWidget(Widget widget, XtCallbackProc callback, XtPointer closure)
  3666. {
  3667.     TipInfo* info;
  3668.  
  3669.     if (callback != NULL) {
  3670.         info = TipInfoNew((XtPointer)widget, callback, closure);
  3671. #ifdef USE_TIP_WIDGET_LIST
  3672.         TipInfoListInsert(&tips_widget_list, info);
  3673. #endif
  3674.         XtAddCallback(widget, XmNdestroyCallback, tips_widget_death_cb, info);
  3675.     } else {
  3676.         info = &tips_no_callback_info;
  3677.     }
  3678.     return info;
  3679. }
  3680.  
  3681. void
  3682. fe_cleanup_tooltips(MWContext *context)
  3683. {
  3684.     fe_tool_tips_widget = NULL;
  3685.  
  3686.     /*
  3687.      *    Stage two? Any event should zap that.
  3688.      */
  3689.     if (fe_tool_tips_shell) {
  3690.     XtDestroyWidget(fe_tool_tips_shell);
  3691.     fe_tool_tips_shell = NULL;
  3692.  
  3693.     /* Mark the tooltips not showing */
  3694.     fe_tooltip_is_showing = False;
  3695.     }
  3696.     
  3697.     /*
  3698.      *   Stage one?
  3699.      */
  3700.     if (fe_tool_tips_timer_id) {
  3701.     XtRemoveTimeOut(fe_tool_tips_timer_id);
  3702.     fe_tool_tips_timer_id = 0;
  3703.     }
  3704. }
  3705.  
  3706. static XP_Bool
  3707. fe_display_docString(MWContext* context,
  3708.                      Widget widget, TipInfo* info, XEvent* event,
  3709.                      Boolean erase)
  3710. {
  3711.     char *s;
  3712.  
  3713.     if (!erase) {
  3714.  
  3715.         s = NULL;
  3716.  
  3717.         /*
  3718.          *    Do callback so user can change the string.
  3719.          */
  3720.         if (info->m_callback != NULL) {
  3721.             XFE_TipStringCallbackStruct cb_info;
  3722.             
  3723.             cb_info.reason = XFE_DOCSTRING;
  3724.             cb_info.event = event;
  3725.             cb_info.string = &s;
  3726.             /* Tao
  3727.              */
  3728.             cb_info.x = info->x;
  3729.             cb_info.y = info->y;
  3730.  
  3731.             (*info->m_callback)(widget, info->m_closure, &cb_info);
  3732.         }
  3733.  
  3734.         if (s == NULL) 
  3735.         {
  3736.             s = XfeSubResourceGetWidgetStringValue(widget,
  3737.                                                    "documentationString",
  3738.                                                    "DocumentationString");
  3739.         }
  3740.  
  3741.     } else { /* erasing */
  3742.         s = "";
  3743.     }
  3744.     
  3745. #ifdef DEBUG
  3746.     if (s == NULL) {
  3747.         static char buf[128];
  3748.         s = buf;    
  3749.         sprintf(s, "Debug: no documentationString resource for widget %s",
  3750.                 XtName(widget));
  3751.     }
  3752. #endif /*DEBUG*/
  3753.  
  3754.     if (context == NULL || s == NULL)
  3755.         return False;
  3756.  
  3757.     XFE_Progress(context, s);
  3758.  
  3759.     return True;
  3760. }
  3761.  
  3762. static void
  3763. fe_tooltips_display_stage_one(Widget widget, XEvent* event,
  3764.                               TipInfo* info, Boolean begin)
  3765. {
  3766.     MWContext* context = fe_WidgetToMWContext(widget);
  3767.     if (context)
  3768.         fe_display_docString(context, widget, info, event, !begin);
  3769. }
  3770.  
  3771. static Widget
  3772. fe_tooltip_create_effects(Widget parent, char* name, char* string)
  3773. {
  3774.     Widget shell;
  3775.     Widget label;
  3776.     Visual *v = 0;
  3777.     Colormap cmap = 0;
  3778.     Cardinal depth = 0;
  3779.     XmFontList fontList;
  3780.     XmString xm_string;
  3781.  
  3782.     shell = parent;
  3783.     while (XtParent(shell) && !XtIsShell(shell)) {
  3784.     shell = XtParent(shell);
  3785.     }
  3786.  
  3787.     if (shell == NULL || XtParent(shell) == NULL)
  3788.         return NULL;
  3789.  
  3790.     XtVaGetValues(shell, XtNvisual, &v, XtNcolormap, &cmap,
  3791.            XtNdepth, &depth, 0);
  3792.  
  3793.     XtVaGetValues(parent, XmNfontList, &fontList, NULL);
  3794.  
  3795.     shell = XtVaCreateWidget(name,
  3796.                  overrideShellWidgetClass,
  3797.                  XtParent(shell), /* the app */
  3798.                  XmNvisual, v,
  3799.                  XmNcolormap, cmap,
  3800.                  XmNdepth, depth,
  3801.                  XmNborderWidth, 1,
  3802.                  NULL);
  3803.  
  3804.     xm_string = XmStringCreateLocalized(string);
  3805.  
  3806.     label = XtVaCreateManagedWidget("tipLabel",
  3807.                     xmLabelWidgetClass,
  3808.                     shell,
  3809.                     XmNlabelType, XmSTRING,
  3810.                     XmNlabelString, xm_string,
  3811.                     NULL);
  3812.     XmStringFree(xm_string);
  3813.     XtManageChild(label);
  3814.  
  3815.     return label;
  3816. }
  3817.  
  3818. static Widget
  3819. fe_tooltips_display_stage_two(Widget widget, TipInfo* info)
  3820. {
  3821.     Widget parent;
  3822.     Widget label;
  3823.     Dimension width;
  3824.     Dimension border_width;
  3825.     Dimension height;
  3826.     Position x_root;
  3827.     Position y_root;
  3828.     Position y_root_orig;
  3829.     Screen* screen;
  3830.     Position x_info = 0;
  3831.     Position y_info = 0;
  3832.  
  3833.     char* s = XfeSubResourceGetWidgetStringValue(widget, 
  3834.                                                  "tipString", 
  3835.                                                  "TipString");
  3836.  
  3837.     /*
  3838.      *    Do callback so user can change the string.
  3839.      */
  3840.     if (info->m_callback != NULL) {
  3841.         XFE_TipStringCallbackStruct cb_info;
  3842.         XAnyEvent any_event;
  3843.  
  3844.         any_event.type = -1;
  3845.         any_event.serial = 0;
  3846.         any_event.send_event = False;
  3847.         any_event.display = XtDisplay(widget);
  3848.         any_event.window = XtWindow(widget);
  3849.  
  3850.         cb_info.reason = XFE_TIPSTRING;
  3851.         cb_info.event = (XEvent*)&any_event;
  3852.         cb_info.string = &s;
  3853.  
  3854.         /* Tao
  3855.          */
  3856.         cb_info.x = info->x;
  3857.         cb_info.y = info->y;
  3858.  
  3859.         (*info->m_callback)(widget, info->m_closure, &cb_info);
  3860.  
  3861.         /* Tao
  3862.          */
  3863.         x_info = cb_info.x;
  3864.         y_info = cb_info.y;
  3865.     }
  3866.  
  3867. #ifdef DEBUG
  3868.     if (s == NULL && 
  3869.         !(info->rePosition &&
  3870.           x_info >= 0 && 
  3871.           y_info >= 0)) {/* prompt debug tooltip iff it is not a grid/html view
  3872.                                */
  3873.         static char buf[256];
  3874.         s = buf;
  3875.         sprintf(s, "Debug: no tipString resource for widget %s\n"
  3876.                 "This message only appears in a DEBUG build",
  3877.                 XtName(widget));
  3878.     }
  3879. #endif /*DEBUG*/
  3880.  
  3881.     if (s == NULL || !XP_STRLEN(s))
  3882.       return NULL;
  3883.  
  3884.     parent = XtParent(widget);
  3885.  
  3886.     label = fe_tooltip_create_effects(parent, "tipShell", s);
  3887.     if (label == NULL)
  3888.         return NULL;
  3889.  
  3890.     parent = XtParent(label);
  3891.  
  3892.     /* Tao: compute x, y only when x_info && y_info is not set
  3893.      */
  3894.         /* francis: yes, but do that before making sure it fits on the screen */
  3895.  
  3896.     XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, 0);
  3897.     XtTranslateCoords(widget, 0, 0, &x_root, &y_root_orig);
  3898.     x_root += (width/2); /* positon in center of button */
  3899.     y_root = y_root_orig + height + 5;
  3900.  
  3901.     /* moved here by francis; formerly right before XtVaSetValues(), below */
  3902.     /* Tao
  3903.      */
  3904.     if (info->rePosition == True &&
  3905.         x_info >= 0 && 
  3906.         y_info >= 0) {
  3907.         XtTranslateCoords(widget, x_info, y_info, &x_root, &y_root);
  3908.     }/* if */
  3909.  
  3910.     /*
  3911.      *    Make sure it fits on screen.
  3912.      */
  3913.     XtVaGetValues(parent, XmNborderWidth, &border_width, 0);
  3914.     XtVaGetValues(label, XmNwidth, &width, XmNheight, &height, 0);
  3915.     screen = XtScreen(label);
  3916.  
  3917.     height += (2*border_width);
  3918.     width += (2*border_width);
  3919.  
  3920.     if (x_root + width > WidthOfScreen(screen))
  3921.     x_root = WidthOfScreen(screen) - width;
  3922.     else if (x_root < 0)
  3923.     x_root = 0;
  3924.     if (y_root + height > HeightOfScreen(screen))
  3925.     y_root = y_root_orig - height - 5;
  3926.     else if (y_root < 0)
  3927.     y_root = 0;
  3928.  
  3929.     XtVaSetValues(parent, XmNx, x_root, XmNy, y_root, 0);
  3930.  
  3931.     /*
  3932.      *    Make sure the user cannot shoot themselves with a random
  3933.      *    geometry spec. No more attack of the killer tomatoes...djw
  3934.      */
  3935.     {
  3936.         char buf[128];
  3937.         sprintf(buf, "%dx%d", width, height);
  3938.         XtVaSetValues(parent, XmNwidth, width, XmNheight, height,
  3939.                       XmNgeometry, buf, 0);
  3940.     }
  3941.  
  3942.     /* Mark the tooltips showing */
  3943.     fe_tooltip_is_showing = True;
  3944.  
  3945.     XtPopup(parent, XtGrabNone);
  3946.  
  3947.     return parent;
  3948. }
  3949.  
  3950. static void
  3951. fe_tooltips_stage_two_timeout(XtPointer closure, XtIntervalId *id)
  3952. {
  3953.     TipInfo*   info = (TipInfo*)closure;
  3954.     Widget     widget = fe_tool_tips_widget;
  3955.     Widget     shell;
  3956.  
  3957.     /* Clear the timer id that we store in the context as once the timeout
  3958.      * has triggered (that is why we are here), the timeout is automatically
  3959.      * removed. Else our event handler will go and remove the timeout again.
  3960.      */
  3961.     fe_tool_tips_timer_id = 0;
  3962.  
  3963.     if (fe_tool_tips_shell == NULL && widget != NULL) {
  3964.         shell = fe_tooltips_display_stage_two(widget, info);
  3965.         fe_tool_tips_shell = shell;
  3966.     }
  3967.  
  3968. }
  3969.  
  3970. static void
  3971. tip_dummy_demo_cb(Widget widget, XtPointer c, XtPointer d) {}
  3972.  
  3973.  
  3974. static void getGridColsRows(Widget w, int* rows, int* cols)
  3975. {
  3976.     int c_rows, c_cols, h_rows, h_cols, f_rows, f_cols;
  3977.     XP_ASSERT(w);
  3978.  
  3979.     XtVaGetValues(w,
  3980.                   XmNrows, &c_rows,
  3981.                   XmNcolumns, &c_cols,
  3982.                   0);
  3983.     *rows = c_rows;
  3984.     *cols = c_cols;
  3985. }
  3986.  
  3987. static void gridXY2CellTracking(Widget widget, 
  3988.                                 int x, int y, /* input only args. */
  3989.                                 XP_Bool *m_inGrid, /* input/output args. */
  3990.                                 int *m_lastRow, int *m_lastCol, 
  3991.                                 unsigned char *m_lastRowtype, 
  3992.                                 unsigned char *m_lastColtype,
  3993.                                 int *outRow, int *outCol, /* output only args. */
  3994.                                 Boolean *enter, 
  3995.                                 Boolean *leave) /* output only args. */
  3996. {
  3997.     int m_totalLines = 0, 
  3998.         m_numcolumns = 0;
  3999.     int row = 0, 
  4000.         column = 0;
  4001.     unsigned char rowtype = XmCONTENT, 
  4002.                   coltype = XmCONTENT;
  4003.  
  4004.     if (0 > XmLGridXYToRowColumn(widget, x, y,
  4005.                                  &rowtype, &row, &coltype, &column)) {
  4006.         /* In grid; but, not in any cells
  4007.          */
  4008.         /* treat it as a leave
  4009.          */
  4010.         *enter = FALSE;
  4011.         *leave = TRUE;        
  4012.         return;
  4013.     }/* if */
  4014.                     
  4015.     getGridColsRows(widget, &m_totalLines, &m_numcolumns);
  4016.     if ((row < m_totalLines) &&
  4017.         (column < m_numcolumns) &&
  4018.         ((*m_lastRow != row)||
  4019.          (*m_lastCol != column) ||
  4020.          (*m_lastRowtype != rowtype)||
  4021.          (*m_lastColtype != coltype))) {
  4022.  
  4023.         *outRow = (rowtype == XmHEADING)?-1:row;
  4024.         *outCol = column;
  4025.         
  4026.         if (*m_inGrid == False) {
  4027.             *m_inGrid = True;
  4028.             
  4029.             /* enter a cell
  4030.              */
  4031.             *enter = TRUE;
  4032.             *leave = FALSE;
  4033.             
  4034.         }/* if */
  4035.         else {
  4036.             /* Cruising among cells
  4037.              */
  4038.             *enter = TRUE;
  4039.             *leave = TRUE;
  4040.         }/* else */
  4041.         *m_lastRow = row;
  4042.         *m_lastCol = column;
  4043.         *m_lastRowtype = rowtype ;
  4044.         *m_lastColtype  = coltype ;
  4045.     }/* row /col in grid */                
  4046. }/* gridXY2CellTracking() */
  4047.  
  4048. typedef struct {
  4049.     MWContext *context;
  4050. #if DO_NOT_PASS_LAYER_N_EVENT
  4051.     char      *alt_text;
  4052.     int       x;
  4053.     int       y;
  4054. #else
  4055.     CL_Layer  *layer;
  4056.     CL_Event  *layer_event;
  4057. #endif
  4058. } HTMLTipData_t;
  4059.  
  4060. static Widget
  4061. fe_HTMLTips_display_stage_two(Widget widget, HTMLTipData_t* info)
  4062. {
  4063.     Widget parent;
  4064.     Widget label;
  4065.     Dimension width;
  4066.     Dimension border_width;
  4067.     Dimension height;
  4068.     Position x_root;
  4069.     Position y_root;
  4070.     Position y_root_orig;
  4071.     Screen* screen;
  4072.     Position x_info;
  4073.     Position y_info;
  4074.     char* s = NULL;
  4075.  
  4076.     if (!info)
  4077.         return NULL;
  4078.  
  4079.  
  4080.     /*
  4081.      *    Do callback so user can change the string.
  4082.      */
  4083.     {
  4084.         XFE_TipStringCallbackStruct cb_info;
  4085.         cb_info.reason = XFE_TIPSTRING;
  4086.         cb_info.event = (XEvent*) NULL;
  4087.         cb_info.string = &s;
  4088.  
  4089.         cb_info.x = -10;
  4090.         cb_info.y = -10;
  4091. #if DO_NOT_PASS_LAYER_N_EVENT
  4092.         fe_HTMLViewTooltips(info->context, info->x, info->y, info->alt_text,
  4093.                             &cb_info);
  4094. #else
  4095.         fe_HTMLViewTooltips(info->context, info->layer, info->layer_event, 
  4096.                             &cb_info);
  4097. #endif
  4098.         XP_FREEIF(info);
  4099.  
  4100.         x_info = cb_info.x;
  4101.         y_info = cb_info.y;
  4102.     }
  4103.     if (s == NULL || !XP_STRLEN(s))
  4104.       return NULL;
  4105.  
  4106.     parent = XtParent(widget);
  4107.  
  4108.     label = fe_tooltip_create_effects(parent, "tipShell", s);
  4109.     if (label == NULL)
  4110.         return NULL;
  4111.  
  4112.     parent = XtParent(label);
  4113.  
  4114.     /* Tao: compute x, y only when x_info && y_info is not set
  4115.      */
  4116.         /* francis: yes, but do that before making sure it fits on the screen */
  4117.     XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, 0);
  4118.     XtTranslateCoords(widget, 0, 0, &x_root, &y_root_orig);
  4119.     x_root += (width/2); /* positon in center of button */
  4120.     y_root = y_root_orig + height + 5;
  4121.  
  4122.     /* moved here by francis; formerly right before XtVaSetValues(), below */
  4123.     if (x_info >= 0 && 
  4124.         y_info >= 0) {
  4125.         XtTranslateCoords(widget, x_info, y_info, &x_root, &y_root);
  4126.     }/* if */
  4127.     /*
  4128.      *    Make sure it fits on screen.
  4129.      */
  4130.     XtVaGetValues(parent, XmNborderWidth, &border_width, 0);
  4131.     XtVaGetValues(label, XmNwidth, &width, XmNheight, &height, 0);
  4132.     screen = XtScreen(label);
  4133.  
  4134.     height += (2*border_width);
  4135.     width += (2*border_width);
  4136.  
  4137.     if (x_root + width > WidthOfScreen(screen))
  4138.     x_root = WidthOfScreen(screen) - width;
  4139.     else if (x_root < 0)
  4140.     x_root = 0;
  4141.     if (y_root + height > HeightOfScreen(screen))
  4142.     y_root = y_root_orig - height - 5;
  4143.     else if (y_root < 0)
  4144.     y_root = 0;
  4145.  
  4146.     XtVaSetValues(parent, XmNx, x_root, XmNy, y_root, 0);
  4147.  
  4148.     /*
  4149.      *    Make sure the user cannot shoot themselves with a random
  4150.      *    geometry spec. No more attack of the killer tomatoes...djw
  4151.      */
  4152.     {
  4153.         char buf[128];
  4154.         sprintf(buf, "%dx%d", width, height);
  4155.         XtVaSetValues(parent, XmNwidth, width, XmNheight, height,
  4156.                       XmNgeometry, buf, 0);
  4157.     }
  4158.  
  4159.     /* Mark the tooltips showing */
  4160.     fe_tooltip_is_showing = True;
  4161.  
  4162.     XtPopup(parent, XtGrabNone);
  4163.  
  4164.     /* free s ; from XP_STRDUP
  4165.      */
  4166.     XP_FREEIF(s);
  4167.     return parent;
  4168. }
  4169.  
  4170. static void
  4171. fe_HTMLTips_stage_two_timeout(XtPointer closure, XtIntervalId *id)
  4172. {
  4173.     Widget         widget = fe_tool_tips_widget;
  4174.     Widget         shell;
  4175.     HTMLTipData_t *tipInfo = (HTMLTipData_t *) closure;
  4176.  
  4177.     /* Clear the timer id that we store in the context as once the timeout
  4178.      * has triggered (that is why we are here), the timeout is automatically
  4179.      * removed. Else our event handler will go and remove the timeout again.
  4180.      */
  4181.     fe_tool_tips_timer_id = 0;
  4182.  
  4183.     if (fe_tool_tips_shell == NULL && widget != NULL) {
  4184.         shell = fe_HTMLTips_display_stage_two(widget, tipInfo);
  4185.         fe_tool_tips_shell = shell;
  4186.     }
  4187.  
  4188. }
  4189.  
  4190. extern void
  4191. fe_HTMLViewTooltipsEH(MWContext *context, CL_Layer *layer,
  4192.                       CL_Event *layer_event, int state)
  4193. {
  4194.     Widget widget = CONTEXT_DATA(context)->drawing_area;
  4195.     Boolean enter;
  4196.     Boolean leave;
  4197.     Boolean tips_enabled;
  4198.  
  4199.     enter = FALSE;
  4200.     leave = FALSE;
  4201.     if (state == 2 || state == 3) {
  4202.         enter = TRUE;
  4203.         leave = TRUE;        
  4204.     } /* if */
  4205.     else if (state == 1) {
  4206.         enter = TRUE;
  4207.         leave = FALSE;
  4208.     }/* else if */
  4209.     else if (state == 4) {
  4210.         enter = FALSE;
  4211.         leave = TRUE;
  4212.  
  4213.     }/* else if */
  4214.     else { /* clicks, pops, squeaks, and other non-motionals */
  4215.         enter = FALSE;
  4216.         leave = FALSE;
  4217.     }/* else */
  4218.     
  4219.     /*
  4220.      *    Stage two? Any event should zap that.
  4221.      */
  4222.     if (fe_tool_tips_shell) {
  4223.         /* Mark the tooltips not showing */
  4224.         fe_tooltip_is_showing = False;
  4225.         XtDestroyWidget(fe_tool_tips_shell);
  4226.         fe_tool_tips_shell = NULL;
  4227.     }/* if */
  4228.     
  4229.     /*
  4230.      *   Stage one?
  4231.      */
  4232.     if (fe_tool_tips_timer_id) {
  4233.         XtRemoveTimeOut(fe_tool_tips_timer_id);
  4234.         fe_tool_tips_timer_id = 0;
  4235.     }/* if */
  4236.  
  4237.     if (leave == TRUE) {
  4238.         fe_tool_tips_widget = NULL;
  4239.     }/* if */
  4240.     
  4241.     if (enter == TRUE) {
  4242.         tips_enabled  = fe_globalPrefs.toolbar_tips_p;        
  4243.         if (tips_enabled) {
  4244.             HTMLTipData_t *tipData = 
  4245.                 (HTMLTipData_t *) XP_CALLOC(1, sizeof(HTMLTipData_t));
  4246. #if DO_NOT_PASS_LAYER_N_EVENT
  4247.             LO_Element    *le = NULL;
  4248.             int x = layer_event->x,
  4249.                 y = layer_event->y;
  4250.  
  4251.             le = LO_XYToElement(context, x, y, layer);
  4252.             if (le && 
  4253.                 le->type == LO_IMAGE &&
  4254.                 le->lo_image.alt &&
  4255.                 le->lo_image.alt_len ) {
  4256.                 /* do not set time out unless there is an alt_text to display
  4257.                  */
  4258.  
  4259.                 /* to be free by the caller
  4260.                  */
  4261.                 tipData->alt_text = XP_STRDUP((char *)le->lo_image.alt);
  4262.                 tipData->x = x;
  4263.                 tipData->y = y;
  4264.                 tipData->context = context;
  4265.                 fe_tool_tips_timer_id = 
  4266.                     XtAppAddTimeOut(fe_XtAppContext,
  4267.                                     500, /* whatever */
  4268.                                     fe_HTMLTips_stage_two_timeout,
  4269.                                     tipData);
  4270.             }/* if */
  4271.             else
  4272.                 XP_FREEIF(tipData);
  4273. #else
  4274.  
  4275.             /* fix BSR in XFE_HTMLView::tipCB; freed there
  4276.              */
  4277.             CL_Event *dup = (CL_Event *) XP_CALLOC(1, sizeof(CL_Event));
  4278.             dup->x = layer_event->x;
  4279.             dup->y = layer_event->y;
  4280.  
  4281.             tipData->layer_event = dup;
  4282.             tipData->context = context;
  4283.             tipData->layer = layer;
  4284.             fe_tool_tips_timer_id = 
  4285.                 XtAppAddTimeOut(fe_XtAppContext,
  4286.                                 500, /* whatever */
  4287.                                 fe_HTMLTips_stage_two_timeout,
  4288.                                 tipData);
  4289. #endif
  4290.         }/* if tips_enabled */
  4291.         fe_tool_tips_widget = widget;
  4292.     }/* if */
  4293. }
  4294.  
  4295. #if HANDLE_LEAVE_WIN
  4296. /* HTMLView tooltip eventhanler
  4297.  */
  4298. static void
  4299. fe_HTMLViewTooltips_eh(Widget widget, XtPointer closure, XEvent *event,
  4300.                        Boolean *continue_to_dispatch)
  4301. {
  4302.     MWContext *context = (MWContext *) closure;
  4303.     if (widget && 
  4304.         context && 
  4305.         CONTEXT_DATA(context)&&
  4306.         event &&
  4307.         widget == CONTEXT_DATA(context)->drawing_area &&
  4308.         XfeIsAlive(widget)) {
  4309.         switch (event->type) {
  4310.         case EnterNotify:
  4311.             /* As djw suggested: we treat a window enter as a leave
  4312.              */
  4313.             fe_HTMLViewTooltipsEH(context, 
  4314.                                   (CL_Layer *)NULL, 
  4315.                                   (CL_Event *)NULL, 4);
  4316.             break;
  4317.  
  4318.         case LeaveNotify:
  4319.             fe_HTMLViewTooltipsEH(context, 
  4320.                                   (CL_Layer *)NULL, 
  4321.                                   (CL_Event *)NULL, 4);
  4322.             break;
  4323.  
  4324.         default:
  4325.             break;            
  4326.         }/* switch */
  4327.     }/* if */
  4328. }
  4329.  
  4330. extern void fe_Add_HTMLViewTooltips_eh(MWContext *context) 
  4331. {
  4332.     if (context && 
  4333.         CONTEXT_DATA(context)->drawing_area) {
  4334.         XtAddEventHandler(CONTEXT_DATA(context)->drawing_area,
  4335.                           EnterWindowMask | LeaveWindowMask,
  4336.                           FALSE,
  4337.                           fe_HTMLViewTooltips_eh,
  4338.                           context);
  4339.     }/* if */
  4340. }
  4341.  
  4342. extern void fe_Remove_HTMLViewTooltips_eh(MWContext *context) 
  4343. {
  4344.     if (context && 
  4345.         CONTEXT_DATA(context)->drawing_area) {
  4346.         /* send leave to pop down the tooltip
  4347.          */
  4348.         fe_HTMLViewTooltipsEH(context, 
  4349.                               (CL_Layer *)NULL, 
  4350.                               (CL_Event *)NULL, 4);
  4351.  
  4352.         XtRemoveEventHandler(CONTEXT_DATA(context)->drawing_area,
  4353.                              EnterWindowMask | LeaveWindowMask,
  4354.                              FALSE,
  4355.                              fe_HTMLViewTooltips_eh,
  4356.                              context);
  4357.     }/* if */
  4358. }
  4359. #endif /* HANDLE_LEAVE_WIN */
  4360.  
  4361. static void
  4362. fe_tooltips_event_handler(Widget widget, XtPointer closure, XEvent* event,
  4363.                           Boolean* keep_going)
  4364. {
  4365.     TipInfo* info = (TipInfo*)closure;
  4366.     Boolean enter;
  4367.     Boolean leave;
  4368.     Widget  child;
  4369.     Boolean demo;
  4370.     Boolean tips_enabled;
  4371.  
  4372.     Boolean isGridWidget = XtIsSubclass(widget, xmlGridWidgetClass);
  4373.     int x = event->xbutton.x;
  4374.     int y = event->xbutton.y;
  4375.     unsigned char rowtype;
  4376.     unsigned char coltype;
  4377.     int row;
  4378.     int column;
  4379.     static int m_lastRow = -2;
  4380.     static int m_lastCol = -2;
  4381.     static XP_Bool m_inGrid = False;
  4382.     static unsigned char  m_lastRowtype = XmALL_TYPES;
  4383.     static unsigned char  m_lastColtype = XmALL_TYPES;
  4384.  
  4385.    *keep_going = TRUE;
  4386.     
  4387.     if (info != NULL && info->m_callback == tip_dummy_demo_cb) {
  4388.         demo = TRUE;
  4389.     } else {
  4390.         demo = FALSE;
  4391.     }
  4392.     
  4393.     if (event->type == MotionNotify) {
  4394.         enter = FALSE;
  4395.         leave = FALSE;
  4396.         
  4397.         if (info != NULL && info->m_callback == tip_dummy_manager_cb) {
  4398.             TipInfo* ginfo;
  4399.  
  4400.             child = (Widget)_XM_OBJECT_AT_POINT(widget,
  4401.                                                 event->xmotion.x,
  4402.                                                 event->xmotion.y);
  4403.             
  4404.             if (child != NULL
  4405.                 && 
  4406.                 (ginfo = TipInfoListFind(info->m_gadgets, 
  4407.                                          (XtPointer)child)) != NULL) {
  4408.                 info = ginfo;
  4409.                 widget = child;
  4410.                 if (fe_tool_tips_widget == NULL) {
  4411.                     leave = FALSE;
  4412.                     enter = TRUE;
  4413.                 } else if (fe_tool_tips_widget != widget) {
  4414.                     leave = TRUE;
  4415.                     enter = TRUE;
  4416.                 }
  4417.             } else {
  4418.                 if (fe_tool_tips_widget != NULL) {
  4419.                     leave = TRUE;
  4420.                     enter = FALSE;
  4421.                 }
  4422.             }
  4423.         } else { /* motion in non-manager widget */
  4424.             
  4425.             /* Ignore this case if we're dragging.  This fixes
  4426.                tooltips for the ProxyIcon class.  (Otherwise
  4427.                tooltips persist during the drag, bleah.)  CCM */
  4428.             
  4429.             if(!(event->xmotion.state & Button1Mask)) {
  4430.                 if (isGridWidget) {
  4431.                     gridXY2CellTracking(widget, 
  4432.                                 x, y, /* input only args. */
  4433.                                 &m_inGrid, /* input/output args. */
  4434.                                 &m_lastRow, &m_lastCol, 
  4435.                                 &m_lastRowtype, &m_lastColtype,
  4436.                                 &(info->x), &(info->y), /* output only args. */
  4437.                                 &enter, 
  4438.                                 &leave); /* output only args. */
  4439.  
  4440.                 }/* if  Grid */
  4441.                 else if (fe_tool_tips_widget == NULL) {
  4442.                     leave = FALSE;
  4443.                     enter = TRUE;
  4444.                 } else if (fe_tool_tips_widget != widget) {
  4445.                     leave = TRUE;
  4446.                     enter = TRUE;
  4447.                 }
  4448.             }
  4449.         
  4450.             if (leave == FALSE && enter == FALSE) /* motion */
  4451.                 return;
  4452.         }
  4453.     } else if (event->type == EnterNotify) {
  4454.         enter = TRUE;
  4455.         leave = FALSE;
  4456.         if (isGridWidget) {
  4457.             gridXY2CellTracking(widget, 
  4458.                                 x, y, /* input only args. */
  4459.                                 &m_inGrid, /* input/output args. */
  4460.                                 &m_lastRow, &m_lastCol, 
  4461.                                 &m_lastRowtype, &m_lastColtype,
  4462.                                 &(info->x), &(info->y), /* output only args. */
  4463.                                 &enter, 
  4464.                                 &leave); /* output only args. */
  4465.             info->rePosition = True;
  4466.         }/* if */
  4467.      } else if (event->type == LeaveNotify) {
  4468.          enter = FALSE;
  4469.          leave = TRUE;
  4470.          if (isGridWidget) {
  4471.              m_inGrid = False;
  4472.              m_lastRow = m_lastCol = -2;
  4473.              
  4474.              info->x = info->y = -10;
  4475.              info->rePosition = True;
  4476.          }/* if */
  4477.      } else { /* clicks, pops, squeaks, and other non-motionals */
  4478.          enter = FALSE;
  4479.          leave = FALSE;
  4480.      }/* else */
  4481.     
  4482.     /*
  4483.      *    Stage two? Any event should zap that.
  4484.      */
  4485.     if (fe_tool_tips_shell) {
  4486.         /* Mark the tooltips not showing */
  4487.         fe_tooltip_is_showing = False;
  4488.         XtDestroyWidget(fe_tool_tips_shell);
  4489.         fe_tool_tips_shell = NULL;
  4490.     }
  4491.     
  4492.     /*
  4493.      *   Stage one?
  4494.      */
  4495.     if (fe_tool_tips_timer_id) {
  4496.         XtRemoveTimeOut(fe_tool_tips_timer_id);
  4497.         fe_tool_tips_timer_id = 0;
  4498.     }
  4499.     
  4500.     if (leave == TRUE) {
  4501.         if (!isGridWidget)
  4502.             /* outliner does not stage_one doc
  4503.              */
  4504.             fe_tooltips_display_stage_one(widget, 
  4505.                                           event, info, FALSE); /* clear */
  4506.         fe_tool_tips_widget = NULL;
  4507.     }
  4508.     
  4509.     if (enter == TRUE) {
  4510.         if (demo) {
  4511.             tips_enabled = XmToggleButtonGetState(widget);
  4512.         } else {
  4513.             tips_enabled  = fe_globalPrefs.toolbar_tips_p;
  4514.         }
  4515.         
  4516.         if (tips_enabled) {
  4517.             fe_tool_tips_timer_id = XtAppAddTimeOut(fe_XtAppContext,
  4518.                                                     500, /* whatever */
  4519.                                                     fe_tooltips_stage_two_timeout,
  4520.                                                     info);
  4521.         }
  4522.         if (!isGridWidget)
  4523.             /* outliner does not stage_one doc
  4524.              */
  4525.             fe_tooltips_display_stage_one(widget, event, info, TRUE); /* msg */
  4526.         fe_tool_tips_widget = widget;
  4527.     }
  4528. }
  4529.  
  4530. #define TT_EVENT_MASK (PointerMotionMask|EnterWindowMask|LeaveWindowMask| \
  4531.                        ButtonPressMask|ButtonReleaseMask| \
  4532.                        KeyPressMask|KeyReleaseMask)
  4533.  
  4534. void
  4535. fe_AddTipStringCallback(Widget widget,
  4536.                         XtCallbackProc callback, XtPointer closure)
  4537. {
  4538.     TipInfo* info;
  4539.     Boolean  install = False;
  4540.     EventMask mask;
  4541.  
  4542.     if (XtIsSubclass(widget, xmGadgetClass)) {
  4543.  
  4544.         Widget   manager;
  4545.         TipInfo* ginfo;
  4546.  
  4547.         manager = XtParent(widget);
  4548.  
  4549.         if ((info = TipInfoListFind(tips_manager_list,
  4550.                                     (XtPointer)manager)) == NULL) {
  4551.             info = TipInfoNewManager(manager);
  4552.             install = True;
  4553.         }
  4554.  
  4555.         ginfo = TipInfoListFind(info->m_gadgets, (XtPointer)widget);
  4556.  
  4557.         if (ginfo != NULL) {
  4558.             /* print a warning */
  4559.             return;
  4560.         } else {
  4561.             /* create and insert in managers list */
  4562.             ginfo = TipInfoNew((XtPointer)widget, callback, closure);
  4563.             TipInfoListInsert(&info->m_gadgets, ginfo);
  4564.         }
  4565.  
  4566.         widget = manager;
  4567.         mask = TT_EVENT_MASK;
  4568.     } else {
  4569.  
  4570.         if (callback != NULL) {
  4571. #ifdef USE_WIDGET_LIST
  4572.             info = TipInfoListFind(tips_widget_list, widget);
  4573.             if (info != NULL) {
  4574.                 /* print a warning */
  4575.                 return;
  4576.             }
  4577. #endif
  4578.             info = TipInfoNewWidget(widget, callback, closure);
  4579.         } else {
  4580.             info = &tips_no_callback_info;
  4581.         }
  4582.         
  4583.         install = True;
  4584.         mask = TT_EVENT_MASK;
  4585.     }
  4586.  
  4587.     if (!install)
  4588.         return;
  4589.     
  4590.     XtRemoveEventHandler(widget,
  4591.                          mask,
  4592.                          FALSE,
  4593.                          fe_tooltips_event_handler,
  4594.                          info);
  4595.     XtInsertEventHandler(widget,
  4596.                          mask,
  4597.                          FALSE,
  4598.                          fe_tooltips_event_handler,
  4599.                          info,
  4600.                          XtListHead);
  4601. }
  4602.  
  4603. static Boolean
  4604. fe_manager_tt_default_check(Widget widget)
  4605. {
  4606.     return (XtIsSubclass(widget, xmPushButtonGadgetClass)
  4607.         ||
  4608.         XtIsSubclass(widget, xmToggleButtonGadgetClass)
  4609.         ||
  4610.         XtIsSubclass(widget, xmCascadeButtonGadgetClass));
  4611. }
  4612.  
  4613. void
  4614. fe_ManagerAddGadgetToolTips(Widget manager, fe_ToolTipGadgetCheckProc do_class)
  4615. {
  4616.     Widget*  children;
  4617.     Cardinal nchildren;
  4618.     unsigned n;
  4619.  
  4620.     /*
  4621.      *    Now that we keep tipped gadgets on a list, we can use the check
  4622.      *    routine to determien what to install on the manager.
  4623.      */
  4624.     if (!do_class)
  4625.         do_class = fe_manager_tt_default_check;
  4626.  
  4627.     XtVaGetValues(manager,
  4628.                   XmNchildren, &children,
  4629.                   XmNnumChildren, &nchildren,
  4630.                   0);
  4631.     
  4632.     for (n = 0; n < nchildren; n++) {
  4633.         if ((*do_class)(children[n])) {
  4634.             fe_AddTipStringCallback(children[n], NULL, NULL);
  4635.         }
  4636.     }
  4637. }
  4638.  
  4639. /* Document String Only */
  4640. static void fe_docString_hascb_disarm_cb(Widget, XtPointer, XtPointer);
  4641. static void fe_docString_hascb_arm_cb(Widget, XtPointer, XtPointer);
  4642. static void fe_docString_disarm_cb(Widget, XtPointer, XtPointer);
  4643. static void fe_docString_arm_cb(Widget, XtPointer, XtPointer);
  4644.  
  4645. /*
  4646.  *    These callbacks used if the caller provides no callback.
  4647.  *    These guys do not allocate memory, they pass the context around
  4648.  *    as the closure.
  4649.  */
  4650. static void
  4651. fe_docString_disarm_cb(Widget w, XtPointer closure, XtPointer call_data)
  4652. {
  4653.     MWContext* context = (MWContext*)closure;
  4654.     XmPushButtonCallbackStruct* cbs = (XmPushButtonCallbackStruct*)call_data;
  4655.     TipInfo* info = &tips_no_callback_info;
  4656.  
  4657.     fe_display_docString(context, w, info, cbs->event, TRUE);
  4658. }
  4659.  
  4660. static void
  4661. fe_docString_arm_cb(Widget w, XtPointer closure, XtPointer call_data)
  4662. {
  4663.     MWContext* context = (MWContext*)closure;
  4664.     XmPushButtonCallbackStruct* cbs = (XmPushButtonCallbackStruct*)call_data;
  4665.     TipInfo* info = &tips_no_callback_info;
  4666.  
  4667.     if (!fe_display_docString(context, w, info, cbs->event, FALSE)) {
  4668.         /* Arm failed to get any string. Dont waste time from now on for
  4669.          * trying to show the docString everytime we arm this widget.
  4670.          */
  4671.         XtRemoveCallback(w, XmNarmCallback, fe_docString_arm_cb, context);
  4672.         XtRemoveCallback(w, XmNdisarmCallback, fe_docString_disarm_cb, context);
  4673.     }
  4674. }
  4675.  
  4676. /*
  4677.  *    These callbacks used if the caller provides a callback.
  4678.  *    These guys do allocate memory, they store the context in the
  4679.  *    info, and pass the info around as the closure.
  4680.  */
  4681. static void
  4682. tips_button_death_cb(Widget widget, XtPointer closure, XtPointer cb_data)
  4683. {
  4684.     TipInfo* info = (TipInfo*)closure;
  4685.     XtRemoveCallback(widget, XmNdestroyCallback, tips_button_death_cb, info);
  4686.     TipInfoDelete(info);
  4687. }
  4688.  
  4689. static void
  4690. fe_docString_hascb_disarm_cb(Widget w, XtPointer closure, XtPointer call_data)
  4691. {
  4692.     TipInfo* info = (TipInfo*) closure;
  4693.     MWContext* context = (MWContext*)info->m_key;
  4694.     XmPushButtonCallbackStruct* cbs = (XmPushButtonCallbackStruct*)call_data;
  4695.     fe_display_docString(context, w, info, cbs->event, TRUE);
  4696. }
  4697.  
  4698. static void
  4699. fe_docString_hascb_arm_cb(Widget w, XtPointer closure, XtPointer call_data)
  4700. {
  4701.     TipInfo* info = (TipInfo*)closure;
  4702.     MWContext* context = (MWContext*)info->m_key;
  4703.     XmPushButtonCallbackStruct* cbs = (XmPushButtonCallbackStruct*)call_data;
  4704.  
  4705.     if (!fe_display_docString(context, w, info, cbs->event, FALSE)) {
  4706.         /* Arm failed to get any string. Dont waste time from now on for
  4707.          * trying to show the docString everytime we arm this widget.
  4708.          */
  4709.         XtRemoveCallback(w, XmNarmCallback, fe_docString_hascb_arm_cb, context);
  4710.         XtRemoveCallback(w, XmNdisarmCallback,
  4711.                          fe_docString_hascb_disarm_cb, context);
  4712.         tips_button_death_cb(w, (XtPointer)info, call_data);
  4713.     }
  4714. }
  4715.  
  4716. void
  4717. fe_ButtonAddDocStringCallback(MWContext* context, Widget widget,
  4718.                               XtCallbackProc callback, XtPointer closure)
  4719. {
  4720.     TipInfo* info = NULL;
  4721.     
  4722.     if (callback != NULL) {
  4723.         info = TipInfoNew((XtPointer)widget, callback, closure);
  4724.         info->m_key = (TipInfo*)context;
  4725.         XtAddCallback(widget, XmNdestroyCallback, tips_button_death_cb, info);
  4726.         XtAddCallback(widget, XmNarmCallback, fe_docString_hascb_arm_cb, info);
  4727.         XtAddCallback(widget, XmNdisarmCallback,
  4728.                       fe_docString_hascb_disarm_cb, info);
  4729.     } else {
  4730.         XtAddCallback(widget, XmNarmCallback, fe_docString_arm_cb, context);
  4731.         /* Add the disarm callback to erase the document string */
  4732.         XtAddCallback(widget, XmNdisarmCallback, fe_docString_disarm_cb, context);
  4733.     }
  4734. }
  4735.  
  4736. void
  4737. fe_WidgetAddDocumentString(MWContext *context, Widget widget)
  4738. {
  4739.     fe_ButtonAddDocStringCallback(context, widget, NULL, NULL);
  4740. }
  4741.  
  4742.  
  4743. void
  4744. fe_WidgetAddToolTips(Widget widget)
  4745. {
  4746.     fe_AddTipStringCallback(widget, NULL, NULL);
  4747. }
  4748.  
  4749. Widget
  4750. fe_CreateToolTipsDemoToggle(Widget parent, char* name, Arg* args, Cardinal n)
  4751. {
  4752.     Widget widget;
  4753.  
  4754.     widget = XmCreateToggleButton(parent, name, args, n);
  4755.  
  4756.     fe_AddTipStringCallback(widget, tip_dummy_demo_cb, NULL);
  4757.  
  4758.     return widget;
  4759. }
  4760.  
  4761. Boolean
  4762. fe_ManagerCheckGadgetToolTips(Widget manager, fe_ToolTipGadgetCheckProc check)
  4763. {
  4764.     Cardinal   nchildren;
  4765.     WidgetList children;
  4766.     Widget     widget;
  4767.     int        i;
  4768.  
  4769.     if (!check)
  4770.     check = fe_manager_tt_default_check;
  4771.  
  4772.     XtVaGetValues(manager,
  4773.           XmNchildren, &children, XmNnumChildren, &nchildren, 0);
  4774.  
  4775.     for (i = 0; i < nchildren; i++) {
  4776.     widget = children[i];
  4777.     if ((*check)(widget) == TRUE)
  4778.         return TRUE;
  4779.     }
  4780.     return FALSE;
  4781. }
  4782.  
  4783. Boolean
  4784. fe_ContextHasPopups(MWContext* context)
  4785. {
  4786.     Widget shell = CONTEXT_WIDGET(context);
  4787.  
  4788.     return (XfeNumPopups(shell) > 0);
  4789. }
  4790.  
  4791. /*
  4792.  * Motif 1.2 core dumps if right/left arrow keys are pressed while an option
  4793.  * menu is active. So always use fe_CreateOptionMenu() instead of
  4794.  * XmCreateOptionMenu(). This will create one and set the traversal off
  4795.  * on the popup submenu.
  4796.  * - dp
  4797.  */
  4798. Widget
  4799. fe_CreateOptionMenu(Widget parent, char* name, Arg* p_argv, Cardinal p_argc)
  4800. {
  4801.     Widget menu = (Widget )NULL;
  4802.     Widget submenu = (Widget )NULL;
  4803.  
  4804.     menu = XmCreateOptionMenu(parent, name, p_argv, p_argc);
  4805.  
  4806.     XtVaGetValues(menu, XmNsubMenuId, &submenu, 0);
  4807.     if (submenu)
  4808.       XtVaSetValues(submenu, XmNtraversalOn, False, 0);
  4809.  
  4810.     return menu;
  4811. }
  4812.  
  4813.  
  4814. /*
  4815.  * fe_ProtectContext()
  4816.  *
  4817.  * Sets the dont_free_context_memory variable in the CONTEXT_DATA. This
  4818.  * will prevent the memory for the context and CONTEXT_DATA to be freed
  4819.  * even if the context was destroyed.
  4820.  */
  4821. void
  4822. fe_ProtectContext(MWContext *context)
  4823. {
  4824.   unsigned char del = XmDO_NOTHING;
  4825.  
  4826.   if (!CONTEXT_DATA(context)->dont_free_context_memory)
  4827.     {
  4828.       /* This is the first person trying to protect this context. 
  4829.        * Dont allow the user to destroy this context using the windowmanger
  4830.        * delete menu item.
  4831.        */
  4832.       XtVaGetValues(CONTEXT_WIDGET(context), XmNdeleteResponse, &del, 0);
  4833.       CONTEXT_DATA(context)->delete_response = del;
  4834.       XtVaSetValues(CONTEXT_WIDGET(context),
  4835.             XmNdeleteResponse, XmDO_NOTHING, 0);
  4836.     }
  4837.   CONTEXT_DATA(context)->dont_free_context_memory++;
  4838. }
  4839.  
  4840. /*
  4841.  * fe_UnProtectContext()
  4842.  *
  4843.  * Undo what fe_ProtectContext() does. Unsets dont_free_context_memory
  4844.  * variable in the context_data.
  4845.  */
  4846. void
  4847. fe_UnProtectContext(MWContext *context)
  4848. {
  4849.   XP_ASSERT(CONTEXT_DATA(context)->dont_free_context_memory);
  4850.   if (CONTEXT_DATA(context)->dont_free_context_memory)
  4851.     {
  4852.       CONTEXT_DATA(context)->dont_free_context_memory--;
  4853.       if (!CONTEXT_DATA(context)->dont_free_context_memory) {
  4854.     /* This is the last person unprotecting this context. 
  4855.      * Set the delete_response to what it was before.
  4856.      */
  4857.     XtVaSetValues(CONTEXT_WIDGET(context), XmNdeleteResponse,
  4858.               CONTEXT_DATA(context)->delete_response, 0);
  4859.       }
  4860.     }
  4861. }
  4862.  
  4863. /*
  4864.  * fe_IsContextProtected()
  4865.  *
  4866.  * Return the protection state of the context.
  4867.  */
  4868. Boolean
  4869. fe_IsContextProtected(MWContext *context)
  4870. {
  4871.   return (CONTEXT_DATA(context)->dont_free_context_memory);
  4872. }
  4873.  
  4874. /*
  4875.  * fe_IsContextDestroyed()
  4876.  *
  4877.  * Return if the context was destroyed. This is valid only for protected
  4878.  * contexts.
  4879.  */
  4880. Boolean
  4881. fe_IsContextDestroyed(MWContext *context)
  4882. {
  4883.   return (CONTEXT_DATA(context)->destroyed);
  4884. }
  4885.  
  4886. /* Recurses over children of context, returning True if any context is
  4887.    stoppable. */
  4888. Boolean
  4889. fe_IsContextLooping(MWContext *context)
  4890. {
  4891.     int i = 1;
  4892.     MWContext *child;
  4893.     
  4894.     if (!context)
  4895.         return False;
  4896.     
  4897.     if (CONTEXT_DATA(context)->looping_images_p)
  4898.         return True;
  4899.  
  4900.     while ((child = (MWContext*)XP_ListGetObjectNum (context->grid_children,
  4901.                                                      i++)))
  4902.         if (fe_IsContextLooping(child))
  4903.             return True;
  4904.     
  4905.     return False;
  4906. }
  4907.  
  4908.  
  4909. /* Recurses over children of context, returning True if any context is
  4910.    stoppable. */
  4911. static Boolean
  4912. fe_is_context_stoppable_recurse(MWContext *context)
  4913. {
  4914.     int i = 1;
  4915.     MWContext *child;
  4916.     
  4917.     if (!context)
  4918.         return False;
  4919.     
  4920.     if ((CONTEXT_DATA(context)->loading_images_p &&
  4921.          CONTEXT_DATA(context)->autoload_images_p) ||
  4922.         CONTEXT_DATA(context)->looping_images_p) 
  4923.       return True;
  4924.  
  4925.     while ((child = (MWContext*)XP_ListGetObjectNum (context->grid_children,
  4926.                                                      i++)))
  4927.         if (fe_is_context_stoppable_recurse(child))
  4928.             return True;
  4929.     
  4930.     return False;
  4931. }
  4932.  
  4933.  
  4934. /* Returns True if this is a context whose activity can be stopped. */
  4935. Boolean
  4936. fe_IsContextStoppable(MWContext *context)
  4937. {
  4938.   /* XP_IsContextStoppable checks for mocha threads, too. */
  4939.     return (fe_is_context_stoppable_recurse(context) ||
  4940.             XP_IsContextStoppable(context)); 
  4941. }
  4942.  
  4943.  
  4944. static Widget ToplevelWidget = NULL;
  4945.  
  4946.  
  4947. /*
  4948.  * FE_SetToplevelWidget
  4949.  */
  4950. void
  4951. FE_SetToplevelWidget(Widget toplevel)
  4952. {
  4953.     ToplevelWidget = toplevel;
  4954. }
  4955.  
  4956.  
  4957. /*
  4958.  * FE_GetToplevelWidget
  4959.  */
  4960. Widget
  4961. FE_GetToplevelWidget(void)
  4962. {
  4963.     return ToplevelWidget;
  4964. }
  4965.  
  4966. Time
  4967. fe_GetTimeFromEvent(XEvent* event)
  4968. {
  4969.     Time time;
  4970.  
  4971.     if (event->type == KeyPress || event->type == KeyRelease)
  4972.         time = event->xkey.time;
  4973.     else if (event->type == ButtonPress || event->type == ButtonRelease)
  4974.         time = event->xbutton.time;
  4975.     else
  4976.         time = XtLastTimestampProcessed(event->xany.display);
  4977.  
  4978.     return time;
  4979. }
  4980.  
  4981. /*
  4982.  * Check if Conference is installed 
  4983.  */
  4984. XP_Bool
  4985. fe_IsConferenceInstalled() 
  4986. {
  4987.     /* Note: will use XP registry to check if conference
  4988.      *       is installed when the installer is ready.
  4989.      *       For now, just check if we can find conference...
  4990.      */
  4991.  
  4992.     return (fe_conference_path != NULL);
  4993. }
  4994.  
  4995. /*
  4996.  * Check if Calendar is installed 
  4997.  */
  4998. XP_Bool
  4999. fe_IsCalendarInstalled() 
  5000. {
  5001.     /* Note: will use XP registry to check if the Calendar component
  5002.      *       is installed when the installer is ready.
  5003.      *       For now, just check if we can find ctime...
  5004.      */
  5005.  
  5006.     return (fe_calendar_path != NULL);
  5007. }
  5008.  
  5009. /*
  5010.  * Check if Host on Demand is installed 
  5011.  */
  5012. XP_Bool
  5013. fe_IsHostOnDemandInstalled() 
  5014. {
  5015.     /* Note: will use XP registry to check if the HOD component
  5016.      *       is installed when the installer is ready.
  5017.      */
  5018.  
  5019.     return (fe_host_on_demand_path != NULL);
  5020. }
  5021. /*
  5022.  * Check if polaris is installed
  5023.  */
  5024. XP_Bool
  5025. fe_IsPolarisInstalled() 
  5026. {
  5027.     return (fe_IsCalendarInstalled() || fe_IsHostOnDemandInstalled());
  5028. }
  5029.  
  5030.  
  5031. /*
  5032.  * fe_IsEditorDisabled
  5033.  */
  5034. XP_Bool
  5035. fe_IsEditorDisabled(void)
  5036. {
  5037.     XP_Bool disabled = FALSE;
  5038.  
  5039.     PREF_GetBoolPref("browser.editor.disabled", &disabled);
  5040.  
  5041.     return disabled;
  5042. }
  5043.  
  5044.  
  5045. /* 
  5046.  * Return the URL struct for the brower startup page
  5047.  */
  5048. URL_Struct *
  5049. fe_GetBrowserStartupUrlStruct()
  5050. {
  5051.     char       *bufp = NULL;
  5052.     char       *hist_entry = 0;
  5053.     URL_Struct *url = 0;
  5054.  
  5055.     if (fe_globalPrefs.browser_startup_page == BROWSER_STARTUP_HOME &&
  5056.         fe_globalPrefs.home_document && 
  5057.         *fe_globalPrefs.home_document) {
  5058.         bufp = XP_STRDUP(fe_globalPrefs.home_document);
  5059.     }
  5060.     else if (fe_globalPrefs.browser_startup_page == BROWSER_STARTUP_LAST &&
  5061.              fe_ReadLastUserHistory(&hist_entry)) {
  5062.         bufp = hist_entry;
  5063.     }
  5064.     url = NET_CreateURLStruct(bufp, FALSE);
  5065.     if (bufp) XP_FREE(bufp);
  5066.     return url;
  5067. }
  5068.  
  5069.  
  5070. /*
  5071.  * Get a context that represents the background root window. This is used
  5072.  * at init time to find a context we can use to prompt for passwords,
  5073.  * confirm or alert before any main window contexts get initialized.
  5074.  */
  5075. MWContext *
  5076. FE_GetInitContext(void)
  5077. {
  5078.     static MWContext *rootcx = NULL;
  5079.     MWContext *m_context = NULL;
  5080.     fe_ContextData *fec;
  5081.     struct fe_MWContext_cons *cons;
  5082.     MWContextType type;
  5083.     Widget m_widget;
  5084.     LO_Color *color;
  5085.  
  5086.     if (rootcx) return rootcx;  
  5087.  
  5088.     type = MWContextDialog; /* XXX should be it's own type */
  5089.  
  5090.     m_context = XP_NewContext();
  5091.     if (m_context == NULL) return NULL;
  5092.  
  5093.     fec        = XP_NEW_ZAP (fe_ContextData);
  5094.     if (fec == NULL) {
  5095.         XP_DELETE(m_context);
  5096.         return NULL;
  5097.         }
  5098.  
  5099.     m_context->type = type;
  5100.     m_context->is_editor = False;
  5101.  
  5102.     CONTEXT_DATA (m_context) = fec;
  5103.  
  5104.     /* get cmap.... Set to NULL for nowXXXXX */
  5105.     CONTEXT_DATA (m_context)->colormap = NULL;
  5106.  
  5107.     m_widget = FE_GetToplevelWidget();
  5108.     CONTEXT_WIDGET (m_context) = m_widget;
  5109.  
  5110.     fe_InitRemoteServer (XtDisplay (m_widget));
  5111.  
  5112.     /* add the layout function pointers */
  5113.     m_context->funcs = fe_BuildDisplayFunctionTable();
  5114.     m_context->convertPixX = m_context->convertPixY = 1;
  5115.     m_context->is_grid_cell = FALSE;
  5116.     m_context->grid_parent = NULL;
  5117.  
  5118.     /* set the XFE default Document Character set */
  5119.     CONTEXT_DATA(m_context)->xfe_doc_csid = fe_globalPrefs.doc_csid;
  5120.  
  5121. #ifdef notdef
  5122.     fe_InitIconColors(m_context);
  5123.  
  5124.     fe_LicenseDialog (m_context);
  5125. #endif
  5126.  
  5127.     XtGetApplicationResources (m_widget,
  5128.                                (XtPointer) CONTEXT_DATA (m_context),
  5129.                                fe_Resources, fe_ResourcesSize,
  5130.                                0, 0);
  5131.  
  5132. #ifdef notdef
  5133.     /* Use colors from prefs */
  5134.     color = &fe_globalPrefs.links_color;
  5135.     CONTEXT_DATA(m_context)->link_pixel = 
  5136.         fe_GetPixel(m_context, color->red, color->green, color->blue);
  5137.  
  5138.     color = &fe_globalPrefs.vlinks_color;
  5139.     CONTEXT_DATA(m_context)->vlink_pixel = 
  5140.         fe_GetPixel(m_context, color->red, color->green, color->blue);
  5141.  
  5142.     color = &fe_globalPrefs.text_color;
  5143.     CONTEXT_DATA(m_context)->default_fg_pixel = 
  5144.         fe_GetPixel(m_context, color->red, color->green, color->blue);
  5145.  
  5146.     color = &fe_globalPrefs.background_color;
  5147.     CONTEXT_DATA(m_context)->default_bg_pixel = 
  5148.         fe_GetPixel(m_context, color->red, color->green, color->blue);
  5149.  
  5150.     /*
  5151.      * set the default coloring correctly into the new context.
  5152.      */
  5153.     {
  5154.         Pixel unused_select_pixel;
  5155.         XmGetColors (XtScreen (m_widget),
  5156.                      fe_cmap(m_context),
  5157.                      CONTEXT_DATA (m_context)->default_bg_pixel,
  5158.                      &(CONTEXT_DATA (m_context)->fg_pixel),
  5159.                      &(CONTEXT_DATA (m_context)->top_shadow_pixel),
  5160.                      &(CONTEXT_DATA (m_context)->bottom_shadow_pixel),
  5161.                      &unused_select_pixel);
  5162.     }
  5163. #endif
  5164.     rootcx = m_context;
  5165.     return rootcx;
  5166. }
  5167.  
  5168. void fe_CacheWindowOffset(MWContext *context, int32 sx, int32 sy)
  5169. {
  5170.   CONTEXT_DATA(context)->cachedPos.x=sx;
  5171.   CONTEXT_DATA(context)->cachedPos.y=sy;
  5172. }
  5173.  
  5174. /*
  5175.  * Keep track of tooltip mapping to avoid conflict with fascist shells
  5176.  * that insist on raising themselves - like taskbar and netcaster webtop
  5177.  */
  5178. Boolean fe_ToolTipIsShowing(void)
  5179. {
  5180.     return fe_tooltip_is_showing;
  5181. }
  5182.  
  5183.  
  5184. /* Get URL for referral if there is one. */
  5185. char *fe_GetURLForReferral(History_entry *he)
  5186. {
  5187.     if (!he)
  5188.         return NULL;
  5189.  
  5190.     /* Origin URL takes precedence over address */
  5191. #ifdef DEBUG_mcafee   /* Waiting for norris checkin */
  5192.     if (he && he->origin_url)
  5193.         return XP_STRDUP (he->origin_url);
  5194.     else
  5195. #endif
  5196.       if (he && he->address)
  5197.         return XP_STRDUP (he->address);
  5198.     else
  5199.         return NULL;
  5200. }
  5201.