home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / editor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  173.8 KB  |  6,942 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. /*
  20.    editor.c --- XFE editor functions
  21.    Created: Spencer Murray <spence@netscape.com>, 11-Jan-96.
  22.  */
  23.  
  24.  
  25. #include "mozilla.h"
  26. #include "xfe.h"
  27. #include "selection.h"
  28.  
  29. #include "net.h"
  30.  
  31. #ifdef EDITOR
  32.  
  33. #include <X11/keysym.h>   /* for editor key translation */
  34. #include <Xm/CutPaste.h>   /* for editor key translation */
  35.  
  36.  
  37. #include <Xfe/Xfe.h>        /* for xfe widgets and utilities */
  38.  
  39. #include <xpgetstr.h>     /* for XP_GetString() */
  40. #include <edttypes.h>
  41. #include <edt.h>
  42. #include <layout.h>
  43. #include <layers.h>
  44. #include <secnav.h>
  45. #include <prefapi.h>
  46.  
  47. #include "menu.h"
  48. #include "fonts.h"
  49. #include "felocale.h"
  50. #include "intl_csi.h"
  51.  
  52. #endif  /* EDITOR */
  53.  
  54. #include "xeditor.h"
  55.  
  56. #ifdef EDITOR
  57.  
  58. #include "il_icons.h"           /* Image icon enumeration. */
  59.  
  60. #include "edtplug.h"
  61.  
  62. #define CB_STATIC static      /* let commands.c see it */
  63.  
  64. #define XFE_EDITOR_IM_SUPPORT 1
  65.  
  66. /*  Our event loop doesn't have workprocs, so we can't have two modal
  67.  *  dialog conditions (one from frontend, one from backend)
  68. #define EVENT_LOOP_HAS_WORKPROC
  69. */
  70. extern int XFE_EDITOR_NEW_DOCNAME;
  71. extern int XFE_WARNING_AUTO_SAVE_NEW_MSG;
  72. extern int XFE_FILE_OPEN;
  73. extern int XFE_EDITOR_ALERT_FRAME_DOCUMENT;
  74. extern int XFE_EDITOR_ALERT_ABOUT_DOCUMENT;
  75. extern int XFE_ALERT_SAVE_CHANGES;
  76. extern int XFE_WARNING_SAVE_CHANGES;
  77. extern int XFE_ERROR_GENERIC_ERROR_CODE;
  78. extern int XFE_EDITOR_COPY_DOCUMENT_BUSY;
  79. extern int XFE_EDITOR_COPY_SELECTION_EMPTY;
  80. extern int XFE_EDITOR_COPY_SELECTION_CROSSES_TABLE_DATA_CELL;
  81. extern int XFE_EDITOR_COPY_DOCUMENT_BUSY;
  82. extern int XFE_COMMAND_EMPTY;
  83. extern int XFE_EDITOR_HTML_EDITOR_COMMAND_EMPTY;
  84. extern int XFE_EDITOR_IMAGE_EDITOR_COMMAND_EMPTY;
  85. extern int XFE_ACTION_SYNTAX_ERROR;
  86. extern int XFE_ACTION_WRONG_CONTEXT;
  87. extern int XFE_EDITOR_WARNING_REMOVE_LINK;
  88. extern int XFE_UNKNOWN;
  89. extern int XFE_ERROR_COPYRIGHT_HINT;
  90. extern int XFE_ERROR_SAVING_OPTIONS;
  91. extern int XFE_ERROR_READ_ONLY;
  92. extern int XFE_ERROR_BLOCKED;
  93. extern int XFE_ERROR_BAD_URL;
  94. extern int XFE_ERROR_FILE_OPEN;
  95. extern int XFE_ERROR_FILE_WRITE;
  96. extern int XFE_ERROR_CREATE_BAKNAME;
  97. extern int XFE_ERROR_DELETE_BAKFILE;
  98. extern int XFE_ERROR_WRITING_FILE;
  99. extern int XFE_ERROR_SRC_NOT_FOUND;
  100. extern int XFE_WARNING_SAVE_CONTINUE;
  101. extern int XFE_EDITOR_DOCUMENT_TEMPLATE_EMPTY;
  102. extern int XFE_EDITOR_BROWSE_LOCATION_EMPTY;
  103. extern int XFE_UPLOADING_FILE;
  104. extern int XFE_SAVING_FILE;
  105. extern int XFE_LOADING_IMAGE_FILE;
  106. extern int XFE_FILE_N_OF_N;
  107. extern int XFE_PREPARE_UPLOAD;
  108.  
  109. extern void fe_MailComposeDocumentLoaded(MWContext*);
  110. extern void fe_HackEditorNotifyToolbarUpdated(MWContext* context);
  111.  
  112. static void
  113. fe_Bell(MWContext* context)
  114. {
  115.     XBell(XtDisplay(CONTEXT_WIDGET(context)), 0);
  116. }
  117.  
  118. /*
  119.  *    Utility stuff that should be somewhere else.
  120.  */
  121. static Widget
  122. fe_CreateFormDialog(MWContext* context, char* name)
  123. {
  124.   Widget mainw = CONTEXT_WIDGET(context);
  125.   Widget form;
  126.   Arg    av[20];
  127.   int    ac;
  128.   Visual* v = 0;
  129.   Colormap cmap = 0;
  130.   Cardinal depth = 0;
  131.  
  132.   /*
  133.    *    Inherit MainW attributes.
  134.    */
  135.   XtVaGetValues(mainw, XtNvisual, &v, XtNcolormap, &cmap,
  136.         XtNdepth, &depth, 0);
  137.   ac = 0;
  138.   XtSetArg(av[ac], XmNvisual, v); ac++;
  139.   XtSetArg(av[ac], XmNdepth, depth); ac++;
  140.   XtSetArg(av[ac], XmNcolormap, cmap); ac++;
  141.   XtSetArg(av[ac], XmNtransientFor, mainw); ac++;
  142.  
  143.   XtSetArg(av[ac], XmNallowShellResize, TRUE); ac++;
  144.   XtSetArg(av[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
  145.   XtSetArg(av[ac], XmNautoUnmanage, False); ac++;
  146.  
  147.   form = XmCreateFormDialog(mainw, name, av, ac);
  148.  
  149.   return form;
  150. }
  151.  
  152. static int fe_GetStandardPixmap_pixmapsInitialized;
  153.  
  154. static Pixmap
  155. fe_GetStandardPixmap(MWContext* context, char type)
  156. {
  157.   Widget mainw = CONTEXT_WIDGET(context);
  158.   Arg    av[20];
  159.   int    ac;
  160.   Cardinal depth;
  161.   Screen* screen;
  162.   Pixel   fg;
  163.   Pixel   bg;
  164.   char* name;
  165.   Pixmap pixmap;
  166.  
  167.   switch (type) {
  168.   case XmDIALOG_ERROR:       name = "xm_error";       break;
  169.   case XmDIALOG_INFORMATION: name = "xm_information"; break;
  170.   case XmDIALOG_QUESTION:    name = "xm_question";    break;
  171.   case XmDIALOG_WARNING:     name = "xm_warning";     break;
  172.   case XmDIALOG_WORKING:     name = "xm_working";     break;
  173.   default:
  174.     return XmUNSPECIFIED_PIXMAP;
  175.   }
  176.  
  177.   /*
  178.    *    This is so broken. Init MesageBox class, so the Motif
  179.    *    standard icons get installed. YUCK..djw
  180.    */
  181.   if (!fe_GetStandardPixmap_pixmapsInitialized) {
  182.     XtInitializeWidgetClass(xmMessageBoxWidgetClass);
  183.     fe_GetStandardPixmap_pixmapsInitialized++;
  184.   }
  185.  
  186.   /*
  187.    *    Inherit MainW attributes.
  188.    */
  189.   ac = 0;
  190.   XtSetArg(av[ac], XmNbackground, &bg); ac++;
  191.   XtSetArg(av[ac], XmNforeground, &fg); ac++;
  192.   XtSetArg(av[ac], XmNdepth, &depth); ac++;
  193.   XtSetArg(av[ac], XmNscreen, &screen); ac++;
  194.   XtGetValues(mainw, av, ac);
  195.  
  196.   pixmap = XmGetPixmapByDepth(screen, name, fg, bg, depth);
  197.   if (pixmap == XmUNSPECIFIED_PIXMAP) {
  198.     char default_name[256];
  199.  
  200.     strcpy(default_name, "default_");
  201.     strcat(default_name, name);
  202.  
  203.     pixmap = XmGetPixmapByDepth(screen, default_name, fg, bg, depth);
  204.   }
  205.  
  206.   return pixmap;
  207. }
  208.  
  209. XtPointer
  210. fe_GetUserData(Widget widget)
  211. {
  212.     void* rv;
  213.     XtVaGetValues(widget, XmNuserData, &rv, 0);
  214.     return rv;
  215. }
  216.  
  217. static struct {
  218.   unsigned type;
  219.   char*    name;
  220. } fe_CreateYesToAllDialog_button_data[] = {
  221.   { XFE_DIALOG_YES_BUTTON,      "yes"      }, 
  222.   { XFE_DAILOG_YESTOALL_BUTTON, "yesToAll" },
  223.   { XFE_DIALOG_NO_BUTTON,       "no"       },
  224.   { XFE_DIALOG_NOTOALL_BUTTON,  "noToAll"  },
  225.   { XFE_DIALOG_CANCEL_BUTTON,   "cancel"   },
  226.   { 0, NULL }
  227. };
  228.  
  229.  
  230.  
  231. #define XFE_YESTOALL_YES_BUTTON      (fe_CreateYesToAllDialog_button_data[0].name)
  232. #define XFE_YESTOALL_YESTOALL_BUTTON (fe_CreateYesToAllDialog_button_data[1].name)
  233. #define XFE_YESTOALL_NO_BUTTON       (fe_CreateYesToAllDialog_button_data[2].name)
  234. #define XFE_YESTOALL_NOTOALL_BUTTON  (fe_CreateYesToAllDialog_button_data[3].name)
  235. #define XFE_YESTOALL_CANCEL_BUTTON   (fe_CreateYesToAllDialog_button_data[4].name)
  236.  
  237. typedef struct {
  238.     Widget widget;
  239.     char*  name;
  240. } GetChildInfo;
  241.  
  242. static XtPointer
  243. fe_YesToAllDialogGetChildMappee(Widget widget, XtPointer data)
  244. {
  245.     GetChildInfo* info = (GetChildInfo*)data;
  246.     char*         name = XtName(widget);
  247.     
  248.     if (strcmp(info->name, name) == 0) {
  249.     info->widget = widget;
  250.     return (XtPointer)1; /* don't look any more */
  251.     }
  252.     return 0;
  253. }
  254.  
  255. Widget
  256. fe_YesToAllDialogGetChild(Widget parent, unsigned char type)
  257. {
  258.   char*        name;
  259.   GetChildInfo info;
  260.  
  261.   switch (type) {
  262.   case XFE_DIALOG_YES_BUTTON:
  263.     name = XFE_YESTOALL_YES_BUTTON;
  264.     break;
  265.   case XFE_DAILOG_YESTOALL_BUTTON:
  266.     name = XFE_YESTOALL_YESTOALL_BUTTON;
  267.     break;
  268.   case XFE_DIALOG_NO_BUTTON:
  269.     name = XFE_YESTOALL_NO_BUTTON;
  270.     break;
  271.   case XFE_DIALOG_NOTOALL_BUTTON:
  272.     name = XFE_YESTOALL_NOTOALL_BUTTON;
  273.     break;
  274.   case XFE_DIALOG_CANCEL_BUTTON:
  275.     name = XFE_YESTOALL_CANCEL_BUTTON;
  276.     break;
  277.   default:
  278.     return NULL; /* kill, kill, kill */
  279.   }
  280.  
  281.   info.name = name;
  282.   info.widget = NULL;
  283. #ifdef OSF1
  284.   fe_WidgetTreeWalk(parent, fe_YesToAllDialogGetChildMappee, (void *)&info);
  285. #else
  286.   fe_WidgetTreeWalk(parent, fe_YesToAllDialogGetChildMappee, &info);
  287. #endif
  288.  
  289.   return info.widget;
  290. }
  291.  
  292. static Widget
  293. fe_CreateYesToAllDialog(MWContext* context, char* name, Arg* p_av, Cardinal p_ac)
  294. {
  295.   Arg      av[20];
  296.   Cardinal ac;
  297.   Widget   form;
  298.   Widget   children[16];
  299.   Cardinal nchildren = 0;
  300.   Pixmap   pixmap;
  301.   char* bname;
  302.   Widget button;
  303.   Widget icon;
  304.   Widget text;
  305.   Widget separator;
  306.   Widget row;
  307.   int i;
  308.   XtCallbackRec* button_callback_rec = NULL;
  309.   XmString msg_string = NULL;
  310.   char namebuf[64];
  311.   char pixmapType = XmDIALOG_WARNING;
  312.  
  313.   for (i = 0; i < p_ac; i++) {
  314.       if (p_av[i].name == XmNarmCallback)
  315.       button_callback_rec = (XtCallbackRec*)p_av[i].value;
  316.       else if (p_av[i].name == XmNmessageString)
  317.       msg_string = (XmString)p_av[i].value;
  318.       else if (p_av[i].name == XmNdialogType)
  319.       pixmapType = (unsigned char)p_av[i].value;
  320.   }
  321.  
  322.   form = fe_CreateFormDialog(context, name);
  323.  
  324.   strcpy(namebuf, name); strcat(namebuf, "Message");
  325.   ac = 0;
  326.   XtSetArg(av[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  327.   XtSetArg(av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  328.   XtSetArg(av[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  329.   XtSetArg(av[ac], XmNorientation, XmHORIZONTAL); ac++;
  330.   XtSetArg(av[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
  331.   XtSetArg(av[ac], XmNisAligned, TRUE); ac++;
  332.   XtSetArg(av[ac], XmNpacking, XmPACK_TIGHT); ac++;
  333.   row = XmCreateRowColumn(form, namebuf, av, ac);
  334.  
  335.   nchildren = 0;
  336.  
  337.   /*
  338.    *    Make pixmap label.
  339.    */
  340.   pixmap = fe_GetStandardPixmap(context, pixmapType);
  341.  
  342.   ac = 0;
  343.   XtSetArg(av[ac], XmNlabelType, XmPIXMAP); ac++;
  344.   XtSetArg(av[ac], XmNlabelPixmap, pixmap); ac++;
  345.   icon = XmCreateLabelGadget(row, "icon", av, ac);
  346.   children[nchildren++] = icon;
  347.  
  348.   /*
  349.    *    Text.
  350.    */
  351.   ac = 0;
  352.   if (msg_string)
  353.     XtSetArg(av[ac], XmNlabelString, msg_string); ac++;
  354.   XtSetArg(av[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
  355.   XtSetArg(av[ac], XmNlabelType, XmSTRING); ac++;
  356.   text = XmCreateLabelGadget(row, "text", av, ac);
  357.   children[nchildren++] = text;
  358.  
  359.   XtManageChildren(children, nchildren); /* children of row */
  360.  
  361.   nchildren = 0;
  362.   children[nchildren++] = row;
  363.  
  364.   /*
  365.    *    Separator.
  366.    */
  367.   ac = 0;
  368.   XtSetArg(av[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
  369.   XtSetArg(av[ac], XmNtopWidget, row); ac++;
  370.   XtSetArg(av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  371.   XtSetArg(av[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  372.   separator = XmCreateSeparatorGadget(form, "separator", av, ac);
  373.   children[nchildren++] = separator;
  374.  
  375.   /*
  376.    *    Yes, YesToAll, No, NoToAll, Cancel.
  377.    */
  378.   strcpy(namebuf, name); strcat(namebuf, "Buttons");
  379.   ac = 0;
  380.   XtSetArg(av[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
  381.   XtSetArg(av[ac], XmNtopWidget, separator); ac++;
  382.   XtSetArg(av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  383.   XtSetArg(av[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  384.   XtSetArg(av[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  385.   XtSetArg(av[ac], XmNorientation, XmHORIZONTAL); ac++;
  386.   XtSetArg(av[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
  387.   XtSetArg(av[ac], XmNisAligned, TRUE); ac++;
  388.   XtSetArg(av[ac], XmNpacking, XmPACK_COLUMN); ac++;
  389.   row = XmCreateRowColumn(form, namebuf, av, ac);
  390.   children[nchildren++] = row;
  391.  
  392.   XtManageChildren(children, nchildren);
  393.  
  394.   nchildren = 0; /* now do buttons */
  395.   button = NULL;
  396.   for (i = 0; (bname = fe_CreateYesToAllDialog_button_data[i].name); i++) {
  397.  
  398.     ac = 0;
  399.     XtSetArg(av[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
  400.     XtSetArg(av[ac], XmNlabelType, XmSTRING); ac++;
  401.     button = XmCreatePushButtonGadget(row, bname, av, ac);
  402.  
  403.     if (button_callback_rec)
  404.       XtAddCallback(
  405.             button,
  406.             XmNactivateCallback,
  407.             button_callback_rec->callback,
  408.             button_callback_rec->closure
  409.             );
  410.     children[nchildren++] = button;
  411.   }
  412.  
  413.   XtManageChildren(children, nchildren);
  414.  
  415.   return form;
  416. }
  417.  
  418. Boolean
  419. fe_EditorDocumentIsSaved(MWContext* context)
  420. {
  421.     History_entry* hist_ent;
  422.  
  423.     if (!context)
  424.         return False;
  425.  
  426.     if (EDT_IS_NEW_DOCUMENT(context))
  427.         return False;
  428.  
  429.     hist_ent = SHIST_GetCurrent(&context->hist);
  430.  
  431.     if (!hist_ent)
  432.         return False;
  433.  
  434.     if (hist_ent->address != NULL && NET_IsLocalFileURL(hist_ent->address))
  435.         return True;
  436.     else
  437.         return False;
  438. }
  439.  
  440.  
  441. Boolean fe_SaveAsDialog(MWContext* context, char* buf, int type);
  442.  
  443. static Boolean
  444. fe_editor_report_file_error(MWContext*   context,
  445.                 ED_FileError code,
  446.                 char*        filename, 
  447.                 Boolean      ask_question)
  448. {
  449.     int   id;
  450.     char* msg;
  451.     char  buf[MAXPATHLEN];
  452.  
  453.     switch (code) {
  454.     case ED_ERROR_READ_ONLY: /* File is marked read-only */
  455.     id = XFE_ERROR_READ_ONLY;
  456.     break;
  457.     case ED_ERROR_BLOCKED: /* Can't write at this time, edit buffer blocked */
  458.     id = XFE_ERROR_BLOCKED;
  459.     break;
  460.     case ED_ERROR_BAD_URL: /* URL was not a "file:" type or no string */
  461.     id = XFE_ERROR_BAD_URL;
  462.     break;
  463.     case ED_ERROR_FILE_OPEN:
  464.     id = XFE_ERROR_FILE_OPEN;
  465.     break;
  466.     case ED_ERROR_FILE_WRITE:
  467.     id = XFE_ERROR_FILE_WRITE;
  468.     break;
  469.     case ED_ERROR_CREATE_BAKNAME:
  470.     case ED_ERROR_FILE_RENAME_TO_BAK:
  471.     id = XFE_ERROR_CREATE_BAKNAME;
  472.     break;
  473.     case ED_ERROR_DELETE_BAKFILE:
  474.     id = XFE_ERROR_DELETE_BAKFILE;
  475.     break;
  476.     case ED_ERROR_SRC_NOT_FOUND:
  477.     id = XFE_ERROR_SRC_NOT_FOUND;
  478.     break;
  479.     default:
  480.     id = XFE_ERROR_GENERIC_ERROR_CODE; /* generic "...code = (%d)" */
  481.     break;
  482.     }
  483.  
  484.     msg = XP_GetString(XFE_ERROR_WRITING_FILE);
  485.     sprintf(buf, msg, filename);
  486.     strcat(buf, "\n\n");
  487.  
  488.     msg = XP_GetString(id);
  489.     sprintf(&buf[strlen(buf)], msg, code);
  490.  
  491.     if (ask_question) {
  492.     strcat(buf, "\n\n");
  493.     strcat(buf, XP_GetString(XFE_WARNING_SAVE_CONTINUE));
  494.     return XFE_Confirm(context, buf);
  495.     } else {
  496.     FE_Alert(context, buf);
  497.     return TRUE;
  498.     }
  499. }
  500.  
  501. static Boolean
  502. fe_editor_save_common(MWContext* context, char* target_url)
  503. {
  504.     History_entry* hist_ent;
  505.     ED_FileError   code;
  506.     Boolean        images;
  507.     Boolean        links;
  508.     Boolean        save_as;
  509.  
  510.     /* url->address is used for filename */
  511.     hist_ent = SHIST_GetCurrent(&context->hist);
  512.  
  513.     if (!hist_ent)
  514.     return FALSE;
  515.  
  516.     /*
  517.      *    Has the title changed since it was last saved?
  518.      */
  519.     if (hist_ent->title && strcmp(hist_ent->title, hist_ent->address) == 0) {
  520.     /*
  521.      *    BE will set this to the new file, if we don't zap it,
  522.      *    BE will retain the old name - yuck!
  523.      */
  524.     XP_FREE(hist_ent->title);
  525.     hist_ent->title = NULL;
  526.     }
  527.  
  528.     if (target_url) { /* save as */
  529.     save_as = TRUE;
  530.     /* fe_EditorPreferencesGetLinksAndImages(context, &links, &images); */
  531.     } else { /* save me */ 
  532.     target_url = hist_ent->address;
  533.     save_as = FALSE;
  534.     /* images = FALSE;
  535.     links = FALSE; */
  536.     }
  537.     /* hardts, now always use prefs for links and images, Save and Save As 
  538.      do the same thing for adjusting links and images */
  539.     fe_EditorPreferencesGetLinksAndImages(context, &links, &images);
  540.  
  541.     /*
  542.      *    Do this before the save starts, as save very quickly gets
  543.      *    asynchronous.
  544.      */
  545.     CONTEXT_DATA(context)->is_file_saving = True;
  546.  
  547.     /*
  548.      *    EDT_SaveFile returns true if it completed immediately.
  549.      *    savesas uses source and dest, save just uses 
  550.      */
  551.     code = EDT_SaveFile(context, hist_ent->address, target_url,
  552.             save_as, images, links);
  553.  
  554.     /* here we spin and spin until all the savings of images
  555.      * and stuff are done so that we get a "real" status back from
  556.      * the backend.  This makes saving semi-synchronous, good for
  557.      * status reporting
  558.      */
  559.     if (code == ED_ERROR_NONE) { /* we didn't error straight away */
  560.         while(CONTEXT_DATA(context)->is_file_saving) {
  561.             /* do nothing, we wait here */
  562.             fe_EventLoop();
  563.         }
  564.     }
  565.  
  566.     code = CONTEXT_DATA(context)->file_save_status;
  567.     if (code != ED_ERROR_NONE) {
  568.     /*
  569.      *    I'm sure if it is bad if the title is NULL, but
  570.      *    just in case..
  571.      */
  572.     if ((hist_ent = SHIST_GetCurrent(&context->hist)) != NULL
  573.         && 
  574.         hist_ent->title == NULL) {
  575.         hist_ent->title = XP_STRDUP(hist_ent->address);
  576.     }
  577.     fe_editor_report_file_error(context, code, target_url, FALSE);
  578.     return FALSE;
  579.     }
  580.  
  581.     return TRUE;
  582. }
  583.  
  584. Boolean
  585. fe_EditorSaveAs(MWContext* context) /* launches dialog */
  586. {
  587.     char filebuf[MAXPATHLEN];
  588.  
  589.     if (fe_SaveAsDialog(context, filebuf, fe_FILE_TYPE_HTML)) {
  590.     
  591.     char urlbuf[MAXPATHLEN];
  592.         
  593.     PR_snprintf(urlbuf, sizeof(urlbuf), "file:%.900s", filebuf);
  594.  
  595.     return fe_editor_save_common(context, urlbuf);
  596.     }
  597.  
  598.     return FALSE;
  599. }
  600.  
  601. Boolean
  602. fe_EditorSave(MWContext* context)
  603. {
  604.     /* 
  605.      *    Always ask the user for the filename once.
  606.      *
  607.      *    if (EDT_IS_NEW_DOCUMENT(context))
  608.      */
  609.     if (!fe_EditorDocumentIsSaved(context)) {
  610.         return fe_EditorSaveAs(context);
  611.     }
  612.  
  613.     return fe_editor_save_common(context, NULL);
  614. }
  615.  
  616. /*
  617.  *    I18N input method support.
  618.  */
  619. #ifdef XFE_EDITOR_IM_SUPPORT
  620. static void
  621. fe_editor_im_deregister(Widget widget, XtPointer closure, XtPointer cb_data)
  622. {
  623.     if (!fe_globalData.editor_im_input_enabled)
  624.         return;
  625.  
  626.     XmImUnregister(widget);
  627. }
  628.  
  629. static void
  630. fe_editor_im_get_coords(MWContext* context, XPoint* point)
  631. {
  632.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  633.     
  634.     if (!fe_globalData.editor_im_input_enabled)
  635.         return;
  636.  
  637.     if (data->running == FALSE && data->showing == FALSE) {
  638.         point->x = 0;
  639.         point->y = 16;
  640.     } else {
  641.         point->x = data->x + data->width - CONTEXT_DATA(context)->document_x;
  642.         point->y = data->y - 2 - CONTEXT_DATA(context)->document_y +
  643.             data->height;
  644.     }
  645. #ifdef DEBUG_rhess2
  646.     fprintf(stderr, "im_point::[ %d, %d ]\n", point->x, point->y);
  647. #endif
  648. }
  649.  
  650. static void
  651. fe_editor_im_init(MWContext* context)
  652. {
  653.     Widget     widget = CONTEXT_DATA(context)->drawing_area;
  654.     Arg        args[8];
  655.     Cardinal   n;
  656.     XmFontList font_list;
  657.     Pixel      bg_pixel;
  658.     Pixel      fg_pixel;
  659.     /* Pixmap     bg_pixmap; */
  660.     XPoint     xmim_point;
  661.     /* int        xmim_height; */
  662.     
  663.     if (!fe_globalData.editor_im_input_enabled)
  664. #ifdef DEBUG_rhess
  665.         {
  666.             fprintf(stderr, "fe_editor_im_init::[ PUNT ]\n");
  667.         }
  668.     else
  669.         {
  670.             fprintf(stderr, "fe_editor_im_init::[ ]\n");
  671.         }
  672. #else
  673.         return;
  674. #endif
  675.  
  676.     XtVaSetValues(CONTEXT_WIDGET(context), XmNallowShellResize, TRUE, NULL);
  677.  
  678.     XmImRegister(widget, 0);
  679.     XtAddCallback(widget, XmNdestroyCallback, fe_editor_im_deregister, NULL);
  680.  
  681.     /*
  682.      *    Should these change dynamically with point?
  683.      */
  684. #ifdef OSF1
  685.     font_list = (void *)fe_GetFont(context, 3, LO_FONT_FIXED);
  686. #else
  687.     font_list = fe_GetFont(context, 3, LO_FONT_FIXED);
  688. #endif
  689.     bg_pixel = CONTEXT_DATA(context)->bg_pixel;
  690.     fg_pixel = CONTEXT_DATA(context)->fg_pixel;
  691.     /* bg_pixmap = CONTEXT_DATA(context)->backdrop_pixmap; */
  692.  
  693.     fe_editor_im_get_coords(context, &xmim_point);
  694.  
  695.     n = 0;
  696.     XtSetArg(args[n], XmNfontList, font_list); n++;
  697.     XtSetArg(args[n], XmNbackground, bg_pixel); n++;
  698.     XtSetArg(args[n], XmNforeground, fg_pixel); n++;
  699.     /* XtSetArg(args[n], XmNbackgroundPixmap, bg_pixmap); n++; */
  700.     XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
  701.     /* XtSetArg(args[n], XmNlineSpace, xmim_height); n++; */
  702.     XmImSetValues(widget, args, n);
  703. }
  704.  
  705. static void
  706. fe_editor_im_set_coords(MWContext* context)
  707. {
  708.     Widget   widget = CONTEXT_DATA(context)->drawing_area;
  709.     Arg      args[8];
  710.     Cardinal n;
  711.     XPoint   xmim_point;
  712.     /* int      xmim_height; */
  713.  
  714.     if (!fe_globalData.editor_im_input_enabled)
  715.         return;
  716.  
  717.     fe_editor_im_get_coords(context, &xmim_point);
  718.  
  719.     n = 0;
  720.     XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
  721.     /* XtSetArg(args[n], XmNlineSpace, xmim_height); n++; */
  722.     XmImSetFocusValues(widget, args, n);
  723. }
  724.  
  725. static void
  726. fe_editor_im_focus_in(MWContext* context)
  727. {
  728.     if (!fe_globalData.editor_im_input_enabled)
  729.         return;
  730.  
  731.     fe_editor_im_set_coords(context);
  732.  
  733.     XtSetKeyboardFocus(CONTEXT_WIDGET(context),
  734.                CONTEXT_DATA(context)->drawing_area);
  735. }
  736.  
  737. static void
  738. fe_editor_im_focus_out(MWContext* context)
  739. {
  740.     Widget widget = CONTEXT_DATA(context)->drawing_area;
  741.  
  742.     if (!fe_globalData.editor_im_input_enabled)
  743.         return;
  744.  
  745.     XmImUnsetFocus(widget);
  746. }
  747. #endif /*XFE_EDITOR_IM_SUPPORT*/
  748.  
  749. static void fe_caret_pause(MWContext* context);
  750. static void fe_caret_unpause(MWContext* context);
  751.  
  752. void
  753. xfe2_EditorImSetCoords(MWContext* context)
  754. {
  755.     fe_editor_im_set_coords(context);
  756. }
  757.  
  758. void
  759. xfe2_EditorCaretShow(MWContext* context)
  760. {
  761.     fe_caret_unpause(context);
  762. }
  763.  
  764. void
  765. xfe2_EditorCaretHide(MWContext* context)
  766. {
  767.     fe_caret_pause(context);
  768. }
  769.  
  770. void
  771. xfe2_EditorWaitWhileContextBusy(MWContext* context)
  772. {
  773.     int  n = 0;
  774.  
  775.     while (XP_IsContextBusy(context)) {
  776.         NET_ProcessNet(0, NET_EVERYTIME_TYPE);
  777. #ifdef MOZ_MAIL_NEWS
  778.         MSG_OnIdle();
  779. #endif
  780. #ifdef DEBUG_rhess
  781.         fprintf(stderr, "tic::[ %d ]\n", n);
  782. #endif
  783.         n++;
  784.     }
  785. }
  786.  
  787. static void
  788. fe_change_focus_eh(Widget w, XtPointer closure, XEvent* event, Boolean* cont)
  789. {
  790.     MWContext* context = (MWContext *)closure;
  791.  
  792.     *cont = TRUE;
  793.     
  794.     if (event->type == FocusIn) 
  795.         {
  796.             fe_caret_unpause(context);
  797. #ifdef XFE_EDITOR_IM_SUPPORT
  798.             fe_editor_im_focus_in(context);
  799. #else
  800.             XtSetKeyboardFocus(CONTEXT_WIDGET(context),
  801.                                CONTEXT_DATA(context)->drawing_area);
  802.  
  803. #endif /*XFE_EDITOR_IM_SUPPORT*/
  804.         } 
  805.     else
  806.         {
  807.             fe_caret_pause(context);
  808. #ifdef XFE_EDITOR_IM_SUPPORT
  809.             fe_editor_im_focus_out(context);
  810. #else
  811.             XtSetKeyboardFocus(CONTEXT_WIDGET(context), NULL);
  812. #endif /*XFE_EDITOR_IM_SUPPORT*/
  813.       }
  814. }
  815.  
  816. /*
  817.  *    Menu stuff.
  818.  */
  819. typedef MWContext MWEditorContext; /* place holder */
  820.  
  821. /*
  822.  *  NOTE: look in EditorFrame.cpp for new implementation...
  823.  */
  824.  
  825. void
  826. xfe2_EditorInit(MWContext* context)
  827. {
  828.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  829. #if 0
  830.     /*
  831.      *    Just cannot get this to do what it is supposed to.
  832.      */
  833.     XtAddEventHandler(CONTEXT_WIDGET(context), PropertyChangeMask,
  834.                       FALSE, (XtEventHandler)fe_property_notify_eh,
  835.                       context);
  836. #endif
  837.  
  838.     if (context->type == MWContextEditor) {
  839.         /*
  840.          * NOTE:  the MWContextMessageComposition has it's own ev handler...
  841.          *
  842.          */
  843. #ifdef DEBUG_rhess
  844.         fprintf(stderr, "tag1::[ %p ]\n", CONTEXT_WIDGET(context));
  845. #endif
  846.         XtAddEventHandler(CONTEXT_WIDGET(context), FocusChangeMask,
  847.                           FALSE, (XtEventHandler)fe_change_focus_eh,
  848.                           context);
  849.     }
  850.  
  851.     /*
  852.      *    Register with input server.
  853.      */
  854. #ifdef XFE_EDITOR_IM_SUPPORT
  855.     fe_editor_im_init(context);
  856. #endif /*XFE_EDITOR_IM_SUPPORT*/
  857.  
  858.     /*
  859.      *  NOTE: initialize the caret data structure... [ may be overkill ]
  860.      */
  861.     data->x = 0;
  862.     data->y = 0;
  863.     data->width = 0;
  864.     data->height = 0;
  865.     data->time = 0;
  866.     data->timer_id = 0;
  867.     data->showing = FALSE;
  868.     data->running = FALSE;
  869.     data->backing_store = 0;
  870. }
  871.  
  872. char*
  873. fe_EditorGetTemplateURL(MWContext* context)
  874. {
  875.     char* template_url = fe_EditorPreferencesGetTemplate(context);
  876.  
  877.     if (template_url == NULL || template_url[0] == '\0') {
  878.         char* msg = XP_GetString(XFE_EDITOR_DOCUMENT_TEMPLATE_EMPTY);
  879.  
  880.         /* The new document template location is not set. */
  881.           if (XFE_Confirm(context, msg)) {
  882.             fe_EditorPreferencesDialogDo(context,
  883.                                      XFE_EDITOR_DOCUMENT_PROPERTIES_GENERAL);
  884.         }
  885.         return NULL;
  886.     }
  887.  
  888.     return template_url;
  889. }
  890.  
  891. char*
  892. fe_EditorGetWizardURL(MWContext* context)
  893. {
  894.     return XFE_WIZARD_TEMPLATE_URL;
  895. }
  896.  
  897. void
  898. fe_EditorDisplaySource(MWContext* context)
  899. {
  900.     EDT_DisplaySource(context);
  901. }
  902.  
  903. void
  904. fe_NukeCaret(MWContext * context)
  905. {
  906.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  907.  
  908. #if DEBUG_rhess2
  909.     fprintf(stderr, "fe_NukeCaret::[ ]\n");
  910. #endif
  911.  
  912.     data->x = 0;
  913.     data->y = 0;
  914.     data->width = 0;
  915.     data->height = 0;
  916.     data->time = 0;
  917.     data->timer_id = 0;
  918.     data->showing = False;
  919.     data->running = False;
  920.     data->backing_store = 0;
  921. }
  922.  
  923. void
  924. fe_EditorCleanup(MWContext* context)
  925. {
  926.     Boolean  as_enabled;
  927.     unsigned as_time;
  928.  
  929.     /*
  930.      *    If they have autosave on, try to do a save. Don't do it
  931.      *    for a new doc, as that'll mean dialogs, and .....
  932.      */
  933.     if (!EDT_IS_NEW_DOCUMENT(context) &&
  934.         (!EDT_IsBlocked(context) && EDT_DirtyFlag(context))) {
  935.         fe_EditorPreferencesGetAutoSave(context, &as_enabled, &as_time);
  936.         if (as_enabled)
  937.             fe_EditorSave(context);
  938.     }
  939.  
  940.     fe_NukeCaret(context);
  941.     EDT_DestroyEditBuffer(context);
  942. }
  943.  
  944. char*
  945. fe_EditorMakeName(MWContext* context, char* buf, unsigned maxsize)
  946. {
  947.     History_entry* entry;
  948.     char*          local_name = NULL;
  949.  
  950.     if (!EDT_IS_NEW_DOCUMENT(context)
  951.     &&
  952.     (entry = SHIST_GetCurrent(&context->hist)) && (entry->address)) {
  953.  
  954.     local_name = NULL;
  955.     if (XP_ConvertUrlToLocalFile(entry->address, &local_name)) {
  956.         FE_CondenseURL(buf, local_name, maxsize);
  957.         XP_FREE(local_name);
  958.     } else {
  959.         FE_CondenseURL(buf, entry->address, maxsize);
  960.     }
  961.     } else {
  962.     strcpy(buf, XP_GetString(XFE_EDITOR_NEW_DOCNAME));
  963.     }
  964.     return buf;
  965. }
  966.  
  967. static Boolean
  968. fe_named_question(MWContext* context, char* name, char* message)
  969. {
  970.     return (Boolean)((int)fe_dialog(CONTEXT_WIDGET (context),
  971.                     name, message,
  972.                     TRUE, 0, TRUE, FALSE, 0));
  973. }
  974.  
  975. Boolean
  976. fe_save_file_check(MWContext* context, Boolean file_must_exist, Boolean autoSaveNew)
  977. {
  978.     int rv;
  979.     char filename[MAXPATHLEN];
  980.     char buf[MAXPATHLEN];
  981.     char dialogmessages[MAXPATHLEN+64];
  982.     Boolean ok_cancel = (file_must_exist && EDT_IS_NEW_DOCUMENT(context));
  983.  
  984.     if (ok_cancel || EDT_DirtyFlag(context)) {
  985.     fe_EditorMakeName(context, filename, sizeof(filename));
  986.     
  987.     if (ok_cancel) {
  988.         /* You must save <filename> as a local file */
  989.         sprintf(buf, XP_GetString(XFE_ALERT_SAVE_CHANGES), filename);
  990.         rv = (fe_named_question(context, "saveNewFile", buf))?
  991.         XmDIALOG_OK_BUTTON: XmDIALOG_CANCEL_BUTTON;
  992.     } else {
  993.         /* Save changes to <filename>? */
  994.         sprintf(buf, XP_GetString(XFE_WARNING_SAVE_CHANGES), filename);
  995.         if (autoSaveNew) {
  996.             sprintf(dialogmessages,"%s\n\n%s", buf,
  997.                     XP_GetString(XFE_WARNING_AUTO_SAVE_NEW_MSG));
  998.             rv = fe_YesNoCancelDialog(context, "autoSaveNew", dialogmessages);
  999.         } else
  1000.             rv = fe_YesNoCancelDialog(context, "saveFile", buf);
  1001.     }
  1002.     
  1003.     if (rv == XmDIALOG_OK_BUTTON)
  1004.         return fe_EditorSave(context);
  1005.     else if (rv == XmDIALOG_CANCEL_BUTTON)
  1006.         return FALSE;
  1007.     }
  1008.     return TRUE;
  1009. }
  1010.  
  1011. XP_Bool
  1012. FE_CheckAndSaveDocument(MWContext* context)
  1013. {
  1014.     return fe_save_file_check(context, TRUE, FALSE);
  1015. }
  1016.  
  1017. XP_Bool 
  1018. FE_CheckAndAutoSaveDocument(MWContext *context)
  1019. {
  1020.     return fe_save_file_check(context, FALSE, TRUE);
  1021. }
  1022.  
  1023. /*
  1024.  *    NOTE: this routine is currently commented out, always returns TRUE.
  1025.  *    Call this to check if we need to force saving file
  1026.  *    Conditions are New, unsaved document and when editing a remote file
  1027.  *    Returns TRUE for all cases except CANCEL by the user in any dialog
  1028.  */
  1029. XP_Bool
  1030. FE_SaveNonLocalDocument(MWContext* context, XP_Bool save_new_document) 
  1031. {
  1032. #if 0
  1033.     History_entry* hist_entry;
  1034.     int type;
  1035.     Boolean links;
  1036.     Boolean images;
  1037.     Boolean save;
  1038.     char filebuf[MAXPATHLEN];
  1039.     char urlbuf[MAXPATHLEN];
  1040.     ED_FileError file_error;
  1041.  
  1042.     if (context == NULL || !EDT_IS_EDITOR(context)) {
  1043.         return TRUE;
  1044.     }
  1045.     
  1046.     hist_entry = SHIST_GetCurrent(&(context->hist));
  1047.     if (!hist_entry || !hist_entry->address)
  1048.         return TRUE;
  1049.     
  1050.     /*
  1051.      */
  1052.     type = NET_URL_Type(hist_entry->address);
  1053.  
  1054.     if ((type >  0 && type != FILE_TYPE_URL && type != FILE_CACHE_TYPE_URL &&
  1055.          type != MAILBOX_TYPE_URL && type != VIEW_SOURCE_TYPE_URL)
  1056.     ||
  1057.     (save_new_document && EDT_IS_NEW_DOCUMENT(context)))
  1058.     {
  1059.     fe_EditorPreferencesGetLinksAndImages(context, &links, &images);
  1060.     fe_DoSaveRemoteDialog(context, &save, &links, &images);
  1061.  
  1062.     if (!save)
  1063.         return FALSE;
  1064.  
  1065. #if 0
  1066.     if (!EDT_IS_NEW_DOCUMENT(context))
  1067.         fe_EditorCopyrightWarningDialogDo();
  1068. #endif
  1069.     
  1070.     if (!fe_SaveAsDialog(context, filebuf, fe_FILE_TYPE_HTML))
  1071.         return FALSE;
  1072.  
  1073.     /*
  1074.      *    Grab the filename while we have it to form file: path.
  1075.      */
  1076.     PR_snprintf(urlbuf, sizeof(urlbuf), "file:%.900s", filebuf);
  1077.  
  1078.     /* the c++ comments are here deliberately so that later
  1079.      * on if we use this code we won't forget to modify it */
  1080.  
  1081.     /* this here is all disabled, we don't use it anymore but if later
  1082.      * on we need to use it again, we should probably make it synchronous
  1083.      */
  1084.  
  1085.     file_error = EDT_SaveFile(context,
  1086.                   hist_entry->address,
  1087.                   urlbuf,
  1088.                   TRUE,
  1089.                   images,
  1090.                   links);
  1091.     
  1092.         if (file_error != ED_ERROR_NONE) {
  1093.         fe_editor_report_file_error(context, file_error, urlbuf,
  1094.                     FALSE);
  1095.         return FALSE;
  1096.     }
  1097.     }
  1098. #endif
  1099.     return TRUE;
  1100. }
  1101.  
  1102.  
  1103. CB_STATIC void
  1104. fe_editor_delete_cb(Widget widget, XtPointer closure, XtPointer call_data)
  1105. {
  1106.     MWContext *context = (MWContext *)closure;
  1107.  
  1108.     fe_UserActivity (context);
  1109.  
  1110.     if (fe_WindowCount == 1) {
  1111.     fe_QuitCallback(widget, closure, call_data);
  1112.     }  else {
  1113.     if (fe_save_file_check(context, FALSE, FALSE))
  1114.         fe_EditorDelete(context);
  1115.     }
  1116. }
  1117.  
  1118. void fe_editor_delete_response(Widget widget, XtPointer closure, XtPointer call_data)
  1119. {
  1120.     fe_editor_delete_cb(widget, closure, call_data);
  1121. }
  1122.  
  1123.  
  1124. Boolean
  1125. fe_EditorCheckUnsaved(MWContext* context)
  1126. {
  1127.     struct fe_MWContext_cons* rest;
  1128.  
  1129.     for (rest = fe_all_MWContexts; rest; rest = rest->next) {
  1130.     MWContext* context = rest->context;
  1131.     if (context->type == MWContextEditor) {
  1132.         if (!fe_save_file_check(context, FALSE, FALSE)) {
  1133.         return FALSE;
  1134.         }
  1135.     }
  1136.     }
  1137.     return TRUE;
  1138. }
  1139.  
  1140. void
  1141. fe_EditorReload(MWContext* context, Boolean super_reload)
  1142. {
  1143.     if (EDT_IS_NEW_DOCUMENT(context))
  1144.         return; /* only from action */
  1145.  
  1146.     if (!FE_CheckAndSaveDocument(context))
  1147.         return;
  1148.  
  1149. #if 0 /* this does not exist! */
  1150.     EDT_Reload(context);
  1151. #else
  1152.     if (super_reload)
  1153.         fe_ReLayout (context, NET_SUPER_RELOAD);
  1154.     else
  1155.         fe_ReLayout (context, NET_NORMAL_RELOAD);
  1156. #endif
  1157. }
  1158.  
  1159. void
  1160. fe_EditorFind(MWContext* context)
  1161. {
  1162.     MWContext* top_context = XP_GetNonGridContext(context);
  1163.     
  1164.     if (!top_context)
  1165.     top_context = context;
  1166.  
  1167.     fe_UserActivity(top_context);
  1168.  
  1169.     fe_FindDialog(top_context, False);
  1170. }
  1171.  
  1172. Boolean
  1173. fe_EditorCanFindAgain(MWContext* context)
  1174. {
  1175.     fe_FindData* find_data = CONTEXT_DATA(context)->find_data;
  1176.     
  1177.     return ((find_data != NULL)
  1178.         &&
  1179.         (find_data->string != NULL)
  1180.         &&
  1181.         (find_data->string[0] != '\0'));
  1182. }
  1183.  
  1184. void
  1185. fe_EditorFindAgain(MWContext* context)
  1186. {
  1187.     MWContext*   top_context = XP_GetNonGridContext(context);
  1188.     fe_FindData* find_data;
  1189.  
  1190.     if (!top_context)
  1191.     top_context = context;
  1192.  
  1193.     fe_UserActivity(top_context);
  1194.  
  1195.     find_data = CONTEXT_DATA(top_context)->find_data;
  1196.  
  1197.   if (fe_EditorCanFindAgain(top_context))
  1198.       fe_FindDialog(top_context, TRUE);
  1199.   else
  1200.       fe_Bell(context);
  1201. }
  1202.  
  1203. Boolean
  1204. fe_EditorCanRemoveLinks(MWContext* context)
  1205. {
  1206.     ED_ElementType type = EDT_GetCurrentElementType(context);
  1207.     Boolean        sensitive = FALSE;
  1208.  
  1209.     if ((type == ED_ELEMENT_TEXT ||
  1210.          type == ED_ELEMENT_SELECTION ||
  1211.          type == ED_ELEMENT_IMAGE)
  1212.         &&
  1213.         EDT_CanSetHREF(context)) {
  1214.         sensitive = TRUE;
  1215.     }
  1216.     return sensitive;
  1217. }
  1218.  
  1219. void
  1220. fe_EditorInsertLinkDialogDo(MWContext* context)
  1221. {
  1222. #if 0
  1223.     if (EDT_IS_NEW_DOCUMENT(context)) {
  1224.         if (!FE_CheckAndSaveDocument(context))
  1225.             return;
  1226.     }
  1227. #endif
  1228.  
  1229.     fe_EditorPropertiesDialogDo(context, XFE_EDITOR_PROPERTIES_LINK_INSERT);
  1230. }
  1231.  
  1232. /* -------------------------------------------------------------- */
  1233.  
  1234. /*
  1235.  *    Size Group.
  1236.  */
  1237.  
  1238. void
  1239. fe_EditorFontSizeSet(MWContext* context, ED_FontSize edt_size)
  1240. {
  1241.     if (edt_size >= EDT_FONTSIZE_MIN && edt_size <= EDT_FONTSIZE_MAX) {
  1242. #if 1
  1243.     EDT_SetFontSize(context, edt_size);
  1244. #else
  1245.     /* this does not work */
  1246.     EDT_CharacterData* edt_cdata = EDT_GetCharacterData(context);
  1247.     edt_cdata->mask = TF_FONT_SIZE;
  1248.     edt_cdata->values = TF_FONT_SIZE;
  1249.     edt_cdata->iSize = edt_size;
  1250.     EDT_SetCharacterData(context, edt_cdata);
  1251.     EDT_FreeCharacterData(edt_cdata);
  1252. #endif
  1253.     } else {
  1254.     fe_Bell(context);
  1255.     }
  1256.  
  1257.     fe_EditorUpdateToolbar(context, TF_FONT_SIZE);
  1258. }
  1259.  
  1260. ED_FontSize
  1261. fe_EditorFontSizeGet(MWContext* context)
  1262. {
  1263.     EDT_CharacterData* edt_cdata = EDT_GetCharacterData(context);
  1264.     intn               edt_size;
  1265.  
  1266.     if (edt_cdata != NULL) {
  1267.         edt_size = edt_cdata->iSize;
  1268.         if (edt_size < EDT_FONTSIZE_MIN)
  1269.             edt_size = ED_FONTSIZE_ZERO;
  1270.         EDT_FreeCharacterData(edt_cdata);
  1271.     } else {
  1272.         edt_size = ED_FONTSIZE_DEFAULT;
  1273.     }
  1274.  
  1275.     return (ED_FontSize)edt_size;
  1276. }
  1277.  
  1278. Widget
  1279. fe_OptionMenuSetHistory(Widget menu, unsigned index)
  1280. {
  1281.     Arg        args[4];
  1282.     Cardinal   n;
  1283.     Widget     cascade;
  1284.     Widget     popup_menu;
  1285.     WidgetList children;
  1286.     Cardinal   nchildren;
  1287.  
  1288.     /*
  1289.      *   Update the label, and set the position of the popup.
  1290.      */
  1291.     cascade = XmOptionButtonGadget(menu);
  1292.  
  1293.     /*
  1294.      *    Get the popup menu from the cascade.
  1295.      */
  1296.     n = 0;
  1297.     XtSetArg(args[n], XmNsubMenuId, &popup_menu); n++;
  1298.     XtGetValues(cascade, args, n);
  1299.  
  1300.     /*
  1301.      *    Get the children of the popup.
  1302.      */
  1303.     n = 0;
  1304.     XtSetArg(args[n], XmNchildren, &children); n++;
  1305.     XtSetArg(args[n], XmNnumChildren, &nchildren); n++;
  1306.     XtGetValues(popup_menu, args, n);
  1307.     if (index < nchildren) {
  1308.     /*
  1309.      *    Finally, set the Nth button as history.
  1310.      */
  1311.     n = 0;
  1312.     XtSetArg(args[n], XmNmenuHistory, children[index]); n++;
  1313.     /* NOTE: set it on the top level menu (strange) */
  1314.     XtSetValues(menu, args, n);
  1315.     
  1316.     return children[index];
  1317.     }
  1318.     return NULL;
  1319. }
  1320.  
  1321. /* -------------------------------------------------------------- */
  1322. /*
  1323.  *    Text Attribute set.
  1324.  */
  1325. void
  1326. fe_EditorCharacterPropertiesSet(MWContext* context, ED_TextFormat values)
  1327. {
  1328.     EDT_CharacterData cdata;
  1329.  
  1330.     memset(&cdata, 0, sizeof(EDT_CharacterData));
  1331.  
  1332.     cdata.mask = TF_ALL_MASK;
  1333.     if (values == TF_NONE) {   /* pop everything */
  1334.     cdata.values = 0;
  1335.     } else if (values == (TF_SERVER|TF_SCRIPT)) {
  1336.     cdata.mask = TF_SERVER|TF_SCRIPT;
  1337.     cdata.values = 0;
  1338.     } else if (values == TF_SERVER || values == TF_SCRIPT) {
  1339.     cdata.mask = TF_SERVER|TF_SCRIPT;
  1340.     cdata.values = values;
  1341.     } else {
  1342.     values &= TF_ALL_MASK; /* don't let them shoot themselves */
  1343.     cdata.values = values;
  1344.     }
  1345.  
  1346.     EDT_SetCharacterData(context, &cdata);
  1347.  
  1348.     fe_EditorUpdateToolbar(context, values);
  1349. }
  1350.  
  1351. ED_TextFormat
  1352. fe_EditorCharacterPropertiesGet(MWContext* context)
  1353. {
  1354.     EDT_CharacterData* edt_cdata = EDT_GetCharacterData(context);
  1355.     ED_TextFormat      values;
  1356.  
  1357.     if (edt_cdata != NULL) {
  1358.         values = edt_cdata->values;
  1359.         EDT_FreeCharacterData(edt_cdata);
  1360.     } else {
  1361.         values = TF_NONE;
  1362.     }
  1363.     
  1364.     return values;
  1365. }
  1366.  
  1367. void
  1368. fe_EditorDoPoof(MWContext* context)
  1369. {
  1370.     Boolean            clear_link = TRUE;
  1371.     EDT_CharacterData* pData;
  1372.     
  1373.     if (EDT_SelectionContainsLink(context)) {
  1374.     /*Do you want to remove the link?*/
  1375.     if (!XFE_Confirm(context,
  1376.              XP_GetString(XFE_EDITOR_WARNING_REMOVE_LINK)))
  1377.         clear_link = FALSE;
  1378.     }
  1379.  
  1380.     if (clear_link) {
  1381.     EDT_FormatCharacter(context, TF_NONE);
  1382.     } else {
  1383.     pData = EDT_GetCharacterData(context);
  1384.         if (pData) {
  1385.             pData->mask = ~TF_HREF;
  1386.             pData->values = TF_NONE;
  1387.             EDT_SetCharacterData(context, pData);
  1388.             EDT_FreeCharacterData(pData);
  1389.         }
  1390.     }
  1391.     fe_EditorUpdateToolbar(context, 0);
  1392. }
  1393.  
  1394. /* -------------------------------------------------------------- */
  1395. /*
  1396.  *    Horizontal Rule.
  1397.  */
  1398. void
  1399. fe_EditorInsertHorizontalRule(MWContext* context)
  1400. {
  1401.     /*
  1402.      *    Hrule is so simple, just use default values
  1403.      *   instead of bringing up properties dialog
  1404.      */
  1405.     EDT_HorizRuleData *pData = EDT_NewHorizRuleData();
  1406.     if (pData) {
  1407.         EDT_InsertHorizRule(context, pData);
  1408.     EDT_FreeHorizRuleData(pData);
  1409.     }
  1410. }
  1411.  
  1412. void
  1413. fe_EditorIndent(MWContext* context, Boolean is_indent)
  1414. {
  1415.     if (is_indent)
  1416.         EDT_Outdent(context);
  1417.     else
  1418.         EDT_Indent(context);
  1419. }
  1420.  
  1421. /* -------------------------------------------------------------- */
  1422. /*
  1423.  *    Align Set.
  1424.  */
  1425. void
  1426. fe_EditorAlignSet(MWContext* pMWContext, ED_Alignment align)
  1427. {
  1428.     ED_ElementType type = EDT_GetCurrentElementType(pMWContext);
  1429.  
  1430.     switch ( type ){
  1431.         case ED_ELEMENT_HRULE:
  1432.         {
  1433.             EDT_HorizRuleData* pData = EDT_GetHorizRuleData(pMWContext);
  1434.             if ( pData ){
  1435.                 pData->align = align;
  1436.                 EDT_SetHorizRuleData(pMWContext, pData);
  1437.             }
  1438.             break;
  1439.         }
  1440.        default: /* For Images, Text, or selection, this will do all: */
  1441.             EDT_SetParagraphAlign( pMWContext, align );
  1442.             break;
  1443.     }
  1444.  
  1445.     fe_EditorUpdateToolbar(pMWContext, 0);
  1446. }
  1447.  
  1448. ED_Alignment
  1449. fe_EditorAlignGet(MWContext* pMWContext)
  1450. {
  1451.    ED_ElementType type = EDT_GetCurrentElementType(pMWContext);
  1452.    EDT_HorizRuleData h_data;
  1453.  
  1454.    if (type == ED_ELEMENT_HRULE) {
  1455.        fe_EditorHorizontalRulePropertiesGet(pMWContext, &h_data);
  1456.        return h_data.align;
  1457.    } else { /* For Images, Text, or selection, this will do all: */
  1458.        return EDT_GetParagraphAlign(pMWContext);
  1459.    }
  1460. }
  1461.  
  1462. /* -------------------------------------------------------------- */
  1463. /*
  1464.  *    List Set.
  1465.  */
  1466. void
  1467. fe_EditorToggleList(MWContext* context, intn tag_type)
  1468. {
  1469.     EDT_ToggleList(context, tag_type);
  1470.  
  1471.     fe_EditorUpdateToolbar(context, 0);
  1472. }
  1473.  
  1474. /* -------------------------------------------------------------- */
  1475. /*
  1476.  *    Paragraph Styles Set.
  1477.  */
  1478. TagType
  1479. fe_EditorParagraphPropertiesGet(MWContext* context)
  1480. {
  1481.     return EDT_GetParagraphFormatting(context);
  1482. }
  1483.  
  1484. void
  1485. fe_EditorParagraphPropertiesSet(MWContext* context, TagType type)
  1486. {
  1487. #if 1
  1488.     TagType paragraph_style = EDT_GetParagraphFormatting(context);
  1489.  
  1490.     if (type != paragraph_style) {
  1491.     EDT_MorphContainer(context, type);
  1492.  
  1493.     fe_EditorUpdateToolbar(context, 0);
  1494.     }
  1495. #else
  1496.     /*
  1497.      *    This seems like the correct code, as it would mean the toolbar
  1498.      *    menu and the properties dialog have the same effect when you set
  1499.      *    a list. But this would be different from the Windows version.
  1500.      *    Do above, the same as Windows.
  1501.      */
  1502.     if (type == P_LIST_ITEM) {
  1503.         EDT_ListData list_data;
  1504.  
  1505.         list_data.iTagType = P_UNUM_LIST;
  1506.         list_data.eType = ED_LIST_TYPE_DISC;
  1507.         list_data.bCompact = FALSE;
  1508.  
  1509.         fe_EditorParagraphPropertiesSetAll(context, type, &list_data,
  1510.                        ED_ALIGN_DEFAULT);
  1511.     } else {
  1512.         fe_EditorParagraphPropertiesSetAll(context, type, NULL,
  1513.                        ED_ALIGN_DEFAULT);
  1514.     }
  1515. #endif
  1516. }
  1517.  
  1518. void
  1519. fe_EditorObjectPropertiesDialogDo(MWContext* context)
  1520. {
  1521.     fe_EditorPropertiesDialogType type;
  1522.     ED_ElementType e_type = EDT_GetCurrentElementType(context);
  1523.  
  1524.     if (e_type == ED_ELEMENT_HRULE)
  1525.         type = XFE_EDITOR_PROPERTIES_HRULE;
  1526.     else if (e_type == ED_ELEMENT_IMAGE)
  1527.         type = XFE_EDITOR_PROPERTIES_IMAGE;
  1528.     else if (e_type == ED_ELEMENT_TARGET)
  1529.         type = XFE_EDITOR_PROPERTIES_TARGET;
  1530.     else if (e_type == ED_ELEMENT_UNKNOWN_TAG)
  1531.         type = XFE_EDITOR_PROPERTIES_HTML_TAG;
  1532.     else { /* character */
  1533.         if (EDT_GetHREF(context))
  1534.             type = XFE_EDITOR_PROPERTIES_LINK;
  1535.         else
  1536.             type = XFE_EDITOR_PROPERTIES_CHARACTER;
  1537.     }
  1538.  
  1539.     /*
  1540.      *    Validate that we can do this kind of dialog right now.
  1541.      */
  1542.     if (fe_EditorPropertiesDialogCanDo(context, type)) {
  1543.         fe_EditorPropertiesDialogDo(context, type);
  1544.     } else {
  1545.         fe_Bell(context);
  1546.     }
  1547. }
  1548.  
  1549. /*
  1550.  *    Caret handling stuff. The caret is just a timed draw onto the
  1551.  *    screen, it doesn't exist in the image.
  1552.  */
  1553. #define FE_CARET_DEFAULT_TIME 500
  1554. #define FE_CARET_FLAGS_BLANK  0x1
  1555. #define FE_CARET_FLAGS_DRAW   0x2
  1556. #define FE_CARET_FLAGS_XOR    0x4
  1557. #define FE_CARET_DEFAULT_WIDTH 5
  1558.  
  1559. static void
  1560. fe_caret_draw(MWContext *context)
  1561. {
  1562.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1563.     Widget    drawing_area = CONTEXT_DATA(context)->drawing_area;
  1564.     Display*  dpy = XtDisplay(drawing_area);
  1565.     Window    win = XtWindow(drawing_area);
  1566.     GC        gc;
  1567.     XGCValues gcv;
  1568.     int       x = data->x;
  1569.     int       y = data->y;
  1570.     unsigned  width = data->width;
  1571.     unsigned  height = data->height;
  1572.  
  1573. #ifdef DEBUG_rhess2
  1574.     fprintf(stderr, "fe_caret_draw::[ ]\n");
  1575. #endif
  1576.  
  1577.     memset(&gcv, ~0, sizeof(gcv));
  1578. #if 0
  1579.     {
  1580.     LO_Color  text_color;
  1581.     LO_Color  bg_color;
  1582.     fe_EditorDocumentGetColors(context, NULL, &bg_color, &text_color,
  1583.                    NULL, NULL, NULL);
  1584.     gcv.foreground = fe_GetPixel(context,
  1585.                  text_color.red,
  1586.                  text_color.green,
  1587.                  text_color.blue);
  1588.     }
  1589. #else
  1590.     gcv.foreground = CONTEXT_DATA(context)->fg_pixel;
  1591. #endif
  1592.     gc = fe_GetGC(drawing_area, GCForeground, &gcv);
  1593.  
  1594.     x -= CONTEXT_DATA(context)->document_x;
  1595.     y -= CONTEXT_DATA(context)->document_y;
  1596.  
  1597.     if ((width & 0x1) != 1)
  1598.     width++;
  1599.     
  1600.     /*
  1601.      *    Hack, hack, hack. Do something pretty david!
  1602.      */
  1603. #if 1
  1604.     XDrawLine(dpy, win, gc, x, y, x + width - 1, y);
  1605.     XDrawLine(dpy, win, gc, x + (width/2), y, x + (width/2), y + height - 1);
  1606.     XDrawLine(dpy, win, gc, x, y + height - 1, x + width - 1, y + height - 1);
  1607. #else
  1608.     XDrawRectangle(dpy, win, gc, x, y, width-1, height-1);
  1609. #endif
  1610.  
  1611.     XFlush(dpy);
  1612. }
  1613.  
  1614.  
  1615. static void
  1616. fe_caret_undraw(MWContext *context)
  1617. {
  1618.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1619.     Widget    drawing_area = CONTEXT_DATA (context)->drawing_area;
  1620.     Display*  dpy = XtDisplay(drawing_area);
  1621. #ifdef DONT_rhess
  1622.     Window    win = XtWindow(drawing_area);
  1623.     GC        gc;
  1624.     XGCValues gcv;
  1625.     Visual*   visual;
  1626.     int       visual_depth;
  1627. #endif
  1628.     int       x = data->x;
  1629.     int       y = data->y;
  1630.     unsigned  width = data->width;
  1631.     unsigned  height = data->height;
  1632.  
  1633. #ifdef DEBUG_rhess2
  1634.     fprintf(stderr, "fe_caret_undraw::[ ]\n");
  1635. #endif
  1636.     {
  1637.         int32 ex = x;
  1638.         int32 ey = y;
  1639.         int32 ew = width + 1;
  1640.         int32 eh = height + 1;
  1641.  
  1642.         if (width > 0  && height > 0) {
  1643.             /*
  1644.              *  NOTE:  don't refresh if it's a 0 pixel box...
  1645.              */
  1646. #ifdef DEBUG_rhess2
  1647.             fprintf(stderr, "fe_caret_undraw::[ %d, %d ][ %d, %d ]\n",
  1648.                     ex, ey, ew, eh);
  1649. #endif
  1650.             fe_RefreshArea(context, ex, ey, ew, eh);
  1651.  
  1652.             XFlush(dpy);
  1653.         }
  1654.     }
  1655. #ifdef DONT_rhess
  1656.     {
  1657.         XExposeEvent event;
  1658.  
  1659.         /* generate an expose */
  1660.         event.type = Expose;
  1661.         event.serial = 0;
  1662.         event.send_event = True;
  1663.         event.display = XtDisplay(CONTEXT_DATA(context)->drawing_area);
  1664.         event.window = XtWindow(CONTEXT_DATA(context)->drawing_area);
  1665.         event.x = x - CONTEXT_DATA(context)->document_x;
  1666.         event.y = y - CONTEXT_DATA(context)->document_y;
  1667.         event.width = width + 1;
  1668.         event.height = height + 1;
  1669.         event.count = 0;
  1670.         XSendEvent(event.display, event.window, 
  1671.                    False, ExposureMask, (XEvent*)&event);
  1672.     }
  1673.     XFlush(dpy);
  1674. #endif
  1675. }
  1676.  
  1677. static void
  1678. fe_caret_update(MWContext* context, XtIntervalId *id)
  1679. {
  1680.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1681.  
  1682. #ifdef DONT_rhess
  1683.     if (data->showing) {
  1684.         fe_caret_undraw(context);
  1685.         data->showing = FALSE;
  1686.     } else {
  1687.         fe_caret_draw(context);
  1688.         data->showing = TRUE;
  1689.     }
  1690.  
  1691.     if (data->running) {
  1692.         data->timer_id = XtAppAddTimeOut(fe_XtAppContext,
  1693.                                          data->time,
  1694.                                          (XtTimerCallbackProc)fe_caret_update,
  1695.                                          context);
  1696.     }
  1697. #else
  1698.     if (data->showing) {
  1699.         fe_caret_draw(context);
  1700.     } else {
  1701.         fe_caret_undraw(context);
  1702.     }
  1703.  
  1704.     data->timer_id = 0;
  1705. #endif
  1706. }
  1707.  
  1708. static void
  1709. fe_caret_cancel(MWContext* context)
  1710. {
  1711.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1712.   
  1713. #ifdef DEBUG_rhess2
  1714.     fprintf(stderr, "fe_caret_cancel::[ ]\n");
  1715. #endif
  1716.  
  1717. #ifdef DONT_rhess
  1718.     if (data->running)
  1719.         XtRemoveTimeOut(data->timer_id);
  1720.  
  1721.     data->running = FALSE;
  1722.  
  1723.     if (data->showing)
  1724.         fe_caret_undraw(context);
  1725.     data->showing = FALSE;
  1726.     
  1727.     if (data->backing_store) {
  1728.         XFreePixmap(XtDisplay(CONTEXT_DATA(context)->drawing_area),
  1729.                     data->backing_store);
  1730.         data->backing_store = 0;
  1731.     }
  1732. #else
  1733.     data->running = False;
  1734.     if (data->showing) {
  1735.         data->showing = False;
  1736.         fe_caret_update(context, NULL);
  1737.     }
  1738. #endif
  1739. }
  1740.  
  1741. static void
  1742. fe_caret_pause(MWContext* context)
  1743. {
  1744.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1745.  
  1746. #ifdef DEBUG_rhess2
  1747.     fprintf(stderr, "fe_caret_pause::[ ]\n");
  1748. #endif
  1749.  
  1750.     if (!data->running) {
  1751.         /* already paused or never started */
  1752.         return;
  1753.     }
  1754. #ifdef DONT_rhess
  1755.     else {
  1756.         XtRemoveTimeOut(data->timer_id);
  1757.     }
  1758.  
  1759.     data->running = FALSE;
  1760.  
  1761.     if (data->showing == FALSE) /* always pause showing */
  1762.         fe_caret_update(context, NULL);
  1763. #else
  1764.     data->running = False;
  1765. #ifdef HOT_CARET_rhess
  1766.     if (!data->showing) {
  1767.         data->showing = True;
  1768. #else
  1769.     if (data->showing) {
  1770.         data->showing = False;
  1771. #endif
  1772.         fe_caret_update(context, NULL);
  1773.     }
  1774. #endif /* DONT_rhess */
  1775. }
  1776.  
  1777. static void
  1778. fe_caret_unpause(MWContext* context)
  1779. {
  1780.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1781.  
  1782. #ifdef DEBUG_rhess2
  1783.     fprintf(stderr, "fe_caret_unpause::[ ]\n");
  1784. #endif
  1785.  
  1786. #ifdef DONT_rhess
  1787.     if (data->running == TRUE || data->showing == FALSE) /* not paused */
  1788.         return;
  1789.  
  1790.     data->showing = FALSE;
  1791.     data->running = TRUE;
  1792.  
  1793.     /*
  1794.      *    Draw and set timer
  1795.      */
  1796.     fe_caret_update(context, NULL);
  1797. #else
  1798.     if ( data->running || data->showing ) /* not paused */
  1799.         return;
  1800.  
  1801.     data->running = True;
  1802.  
  1803.     if (!data->showing) {
  1804.         data->showing = True;
  1805.         fe_caret_update(context, NULL);
  1806.     }
  1807. #endif
  1808. }
  1809.  
  1810. static void
  1811. fe_caret_begin(MWContext* context)
  1812. {
  1813.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1814.  
  1815. #ifdef DEBUG_rhess2
  1816.     fprintf(stderr, "fe_caret_begin::[ ]\n");
  1817. #endif
  1818.  
  1819. #ifdef DONT_rhess
  1820.     data->showing = FALSE;
  1821.     data->time = FE_CARET_DEFAULT_TIME;
  1822.     data->running = TRUE;
  1823.  
  1824.     fe_caret_update(context, NULL);
  1825. #else
  1826.     data->time    = 0;
  1827.     data->running = True;
  1828.     if (!data->showing) {
  1829.         data->showing = True;
  1830.         fe_caret_update(context, NULL);
  1831.     }
  1832. #endif
  1833.  
  1834. #ifdef XFE_EDITOR_IM_SUPPORT
  1835.     fe_editor_im_set_coords(context);
  1836. #endif /* XFE_EDITOR_IM_SUPPORT */
  1837. }
  1838.  
  1839. void
  1840. fe_EditorRefreshArea(MWContext* context, int x, int y, unsigned w, unsigned h)
  1841. {
  1842.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1843.  
  1844.     if (
  1845. #if 0
  1846.         /*
  1847.          *    Don't use x, as LO_RefreshArea tends to redraw full width
  1848.          *    anyway.
  1849.          */
  1850.         ((x < data->x && x + w >= data->x) ||
  1851.          (x < data->x + data->width && x + w >= data->x + data->width))
  1852.         &&
  1853. #endif
  1854.         ((y < data->y && y + h >= data->y) ||
  1855.          (y < data->y + data->height && y + h >= data->y + data->height))) {
  1856.  
  1857. #ifdef DONT_rhess
  1858.         if (data->backing_store) {
  1859.             XFreePixmap(XtDisplay(CONTEXT_DATA(context)->drawing_area),
  1860.                         data->backing_store);
  1861.             data->backing_store = 0;
  1862.         }
  1863.  
  1864.         if (data->running) {
  1865.             XtRemoveTimeOut(data->timer_id);
  1866.             data->showing = TRUE; /* force restart of sequence next */
  1867.         }
  1868.         if (data->showing) {
  1869.             data->showing = FALSE;
  1870.             fe_caret_update(context, NULL);
  1871.         }
  1872. #else
  1873.         if (data->showing) {
  1874.             fe_caret_update(context, NULL);
  1875.         }
  1876. #endif
  1877.     }
  1878. }
  1879.  
  1880. static int fe_LastCoffeeScroll_X = 0;
  1881. static int fe_LastCoffeeScroll_Y = 0;
  1882.  
  1883. static void
  1884. fe_editor_keep_cursor_visible(MWContext* context)
  1885. {
  1886.     fe_EditorCaretData* c_data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  1887.     int x = CONTEXT_DATA(context)->document_x;
  1888.     int y = CONTEXT_DATA(context)->document_y;
  1889.     unsigned win_height = CONTEXT_DATA(context)->scrolled_height;
  1890.     unsigned win_width = CONTEXT_DATA(context)->scrolled_width;
  1891.     Boolean  coffee_scroll = FALSE;
  1892.     int fudge = 20;
  1893.     int pad = 10;
  1894.  
  1895. #ifdef DEBUG_rhess2
  1896.     fprintf(stderr, "fe_editor_keep_cursor_visible::[ ]\n");
  1897. #endif
  1898.  
  1899.     if (c_data->y + c_data->height > y + win_height - fudge) {
  1900.         y = c_data->y + c_data->height - win_height + fudge; /* fudge */
  1901.         if (y + win_height > CONTEXT_DATA(context)->document_height)
  1902.             y = CONTEXT_DATA(context)->document_height - win_height;
  1903.         coffee_scroll = TRUE;
  1904.     } else if (c_data->y < y + pad) {
  1905.         y = c_data->y - pad;
  1906.         if (y < 0)
  1907.             y = 0;
  1908.         coffee_scroll = TRUE;
  1909.     }
  1910.  
  1911.     if (c_data->x + c_data->width > x + win_width - fudge) {
  1912.         x = c_data->x + c_data->width - win_width + fudge;
  1913.         if (x + win_width > CONTEXT_DATA(context)->document_width)
  1914.             x = CONTEXT_DATA(context)->document_width - win_width;
  1915.         coffee_scroll = TRUE;
  1916.     } else if (c_data->x < x + pad) {
  1917.         x = c_data->x - pad;
  1918.         if (x < 0)
  1919.             x = 0;
  1920.         coffee_scroll = TRUE;
  1921.     }
  1922.  
  1923.     if (x == fe_LastCoffeeScroll_X && y == fe_LastCoffeeScroll_Y) {
  1924.         coffee_scroll = False;
  1925.     }
  1926.  
  1927.     if (coffee_scroll) {
  1928.         if (c_data->showing)
  1929.             fe_caret_cancel(context);
  1930. #ifdef DEBUG_rhess2
  1931.         fprintf(stderr, "coffee_scroll::[ %d, %d ][ %d, %d ][ %d, %d ]\n", 
  1932.                 x, y, c_data->x, c_data->y, 
  1933.                 CONTEXT_DATA(context)->document_x,
  1934.                 CONTEXT_DATA(context)->document_y );
  1935. #endif
  1936.         /*
  1937.          *    Collect all pending exposures before we scroll.
  1938.          */
  1939.         fe_SyncExposures(context);
  1940.  
  1941.         fe_ScrollTo(context, x, y);
  1942.     }
  1943.  
  1944.     fe_LastCoffeeScroll_X = x;
  1945.     fe_LastCoffeeScroll_Y = y;
  1946. }
  1947.  
  1948. static void
  1949. fe_editor_keep_pointer_visible_autoscroll(XtPointer, XtIntervalId*);
  1950.  
  1951. static void
  1952. fe_editor_keep_pointer_visible(MWContext* context, int p_x, int p_y)
  1953. {
  1954.     fe_ContextData* data = CONTEXT_DATA(context);
  1955.     fe_EditorAscrollData* ascroll_data
  1956.     = &EDITOR_CONTEXT_DATA(context)->ascroll_data;
  1957.     Boolean coffee_scroll = FALSE;
  1958.     int x = data->document_x;
  1959.     int y = data->document_y;
  1960.     int delta = 0;
  1961.  
  1962. #ifdef DEBUG_rhess2
  1963.     fprintf(stderr, "fe_editor_keep_pointer_visible::[ ]\n");
  1964. #endif
  1965.  
  1966.     if (ascroll_data->timer_id)
  1967.       XtRemoveTimeOut(ascroll_data->timer_id);
  1968.  
  1969.     ascroll_data->delta_x = 0;
  1970.     ascroll_data->delta_y = 0;
  1971.  
  1972.     if (p_y < data->document_y) {
  1973.     coffee_scroll = TRUE;
  1974.     y = p_y;
  1975.     delta = (data->document_y - p_y);
  1976.     ascroll_data->y = p_y;
  1977.     ascroll_data->delta_y = -delta;
  1978.     }
  1979.  
  1980.     if (p_y > data->document_y + data->scrolled_height) {
  1981.     coffee_scroll = TRUE;
  1982.     y = p_y - data->scrolled_height;
  1983.     delta = p_y - (data->document_y + data->scrolled_height);
  1984.     ascroll_data->y = p_y;
  1985.     ascroll_data->delta_y = delta;
  1986.     }
  1987.  
  1988.     if (coffee_scroll) {
  1989.         /*
  1990.          *    Collect all pending exposures before we scroll.
  1991.          */
  1992.         fe_SyncExposures(context);
  1993.  
  1994.         fe_ScrollTo(context, x, y);
  1995.  
  1996.         ascroll_data->timer_id = 
  1997.             XtAppAddTimeOut(fe_XtAppContext,
  1998.                             (100),
  1999.                             fe_editor_keep_pointer_visible_autoscroll,
  2000.                             (XtPointer)context);
  2001.     }
  2002. }
  2003.  
  2004. static void
  2005. fe_editor_keep_pointer_visible_autoscroll(XtPointer closure, XtIntervalId* id)
  2006. {
  2007.     MWContext* context = (MWContext*)closure;
  2008.     fe_EditorAscrollData* ascroll_data;
  2009.  
  2010. #if DEBUG_rhess2
  2011.     fprintf (stderr,"fe_editor_keep_pointer_visible_autoscroll::[ ]\n");
  2012. #endif
  2013.  
  2014.     ascroll_data = &EDITOR_CONTEXT_DATA(context)->ascroll_data;
  2015.     ascroll_data->timer_id = 0; /* because we won't pop again */
  2016.   
  2017.     ascroll_data->x += ascroll_data->delta_x;
  2018.     ascroll_data->y += ascroll_data->delta_y;
  2019.  
  2020.     EDT_ExtendSelection(context, ascroll_data->x, ascroll_data->y);
  2021.  
  2022.     fe_editor_keep_pointer_visible(context, ascroll_data->x, ascroll_data->y);
  2023. }
  2024.  
  2025. static void
  2026. fe_caret_set(MWContext* context, int x, int y, unsigned w, unsigned h)
  2027. {
  2028.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  2029.  
  2030. #ifdef DEBUG_rhess2
  2031.     fprintf(stderr, "fe_caret_set::[ ]\n");
  2032. #endif
  2033.  
  2034.     if ( x != data->x || 
  2035.          y != data->y || 
  2036.          w != data->width || 
  2037.          h != data->height )
  2038.         {
  2039.             if (data->showing)
  2040.                 fe_caret_cancel(context);
  2041.         }
  2042.  
  2043. #ifdef DONT_rhess
  2044.     if (data->running)
  2045.     XtRemoveTimeOut(data->timer_id);
  2046. #endif
  2047.  
  2048.     data->x = x;
  2049.     data->y = y;
  2050.     data->width = w;
  2051.     data->height = h;
  2052.  
  2053.     fe_editor_keep_cursor_visible(context);
  2054. }
  2055.  
  2056. Boolean 
  2057. FE_GetCaretPosition(
  2058.             MWContext *context,
  2059.             LO_Position* where,
  2060.             int32* caretX, int32* caretYLow, int32* caretYHigh
  2061. ) {
  2062.   int32 xVal;
  2063.   int32 yVal;
  2064.   int32 yValHigh;
  2065.  
  2066. #if DEBUG_rhess2
  2067.   fprintf(real_stderr, "FE_GetCaretPosition::[ ]\n");
  2068. #endif
  2069.  
  2070.   if (!context || !where->element)
  2071.     return FALSE;
  2072.   
  2073.   xVal = where->element->lo_any.x + where->element->lo_any.x_offset;
  2074.   yVal = where->element->lo_any.y;
  2075.   yValHigh = yVal + where->element->lo_any.height;
  2076.  
  2077.   switch (where->element->type) {
  2078.   case LO_TEXT: {
  2079.     LO_TextStruct* text_data = & where->element->lo_text;
  2080.     LO_TextInfo    text_info;
  2081.     int            len_save = text_data->text_len;
  2082.  
  2083.     if (!text_data->text_attr)
  2084.       return FALSE;
  2085.  
  2086.     if (where->position <= text_data->text_len) {
  2087.       text_data->text_len = where->position;
  2088.     }
  2089.     XFE_GetTextInfo(context, text_data, &text_info);
  2090.     text_data->text_len = len_save;
  2091.     
  2092.     xVal += text_info.max_width - 1;
  2093.   } break;
  2094.  
  2095.   case LO_IMAGE: {
  2096.     LO_ImageStruct *pLoImage = & where->element->lo_image;
  2097.     if (where->position == 0) {
  2098.       xVal -= 1;
  2099.     } else {
  2100.       xVal += pLoImage->width + 2 * pLoImage->border_width;
  2101.     }
  2102.   } break;
  2103.     
  2104.   default: {
  2105.     LO_Any *any = &where->element->lo_any;
  2106.     if (where->position == 0) {
  2107.       xVal -= 1;
  2108.     } else {
  2109.       xVal += any->width;
  2110.     }
  2111.   }
  2112.   }
  2113.  
  2114.   *caretX = xVal;
  2115.   *caretYLow = yVal;
  2116.   *caretYHigh = yValHigh;
  2117.  
  2118.   return TRUE;
  2119. }
  2120.  
  2121. /*
  2122.  *    char_offset is in characters!!!
  2123.  */
  2124. PUBLIC void
  2125. FE_DisplayTextCaret(MWContext* context, int iLocation, LO_TextStruct* text,
  2126.             int char_offset)
  2127. {
  2128.   int       x;
  2129.   int       y;
  2130.   unsigned  width;
  2131.   unsigned  height;
  2132.   LO_TextInfo text_info;
  2133.   int16     save_len;
  2134.  
  2135. #if DEBUG_rhess2
  2136.   fprintf (stderr,"FE_DisplayTextCaret::[ ]\n");
  2137. #endif
  2138.  
  2139.   /*
  2140.    *    Get info extent info about the first <char_offset> characters of
  2141.    *    text.
  2142.    */
  2143.   save_len = text->text_len;
  2144.   text->text_len = char_offset;
  2145.   XFE_GetTextInfo(context, text, &text_info);
  2146.   x = text->x + text->x_offset + text_info.max_width;
  2147.   y = text->y + text->y_offset;
  2148.   height =  text_info.ascent + text_info.descent;
  2149.   
  2150.   text->text_len = save_len;
  2151.  
  2152.   width = FE_CARET_DEFAULT_WIDTH;
  2153.   x -= (FE_CARET_DEFAULT_WIDTH/2) + 1; /* middle of char and back */
  2154.  
  2155.   fe_caret_set(context, x, y, width, height);
  2156.   fe_caret_begin(context);
  2157. }
  2158.  
  2159. void 
  2160. FE_DisplayImageCaret(
  2161.              MWContext*             context, 
  2162.              LO_ImageStruct*        image,
  2163.              ED_CaretObjectPosition caretPos)
  2164. {
  2165.   int       x;
  2166.   int       y;
  2167.   unsigned  width;
  2168.   unsigned  height;
  2169.   
  2170. #if DEBUG_rhess2
  2171.   fprintf (stderr,"FE_DisplayImageCaret::[ ]\n");
  2172. #endif
  2173.  
  2174.   /*
  2175.    *    Get info extent info about the first <char_offset> characters of
  2176.    *    text.
  2177.    */
  2178.   x = image->x + image->x_offset;
  2179.   y = image->y + image->y_offset;
  2180.   width = FE_CARET_DEFAULT_WIDTH;
  2181.   height = image->height + (2 * image->border_width);
  2182.  
  2183.   if (caretPos == ED_CARET_BEFORE) {
  2184.     x -= 1;
  2185.   } else if (caretPos == ED_CARET_AFTER) {
  2186.     x += image->width + (2 * image->border_width);
  2187.   } else {
  2188.     width = image->width + (2 * image->border_width);
  2189.   }
  2190.  
  2191.   fe_caret_set(context, x, y, width, height);
  2192.   fe_caret_begin(context);
  2193. }
  2194.  
  2195. void FE_DisplayGenericCaret(MWContext * context, LO_Any * image,
  2196.                         ED_CaretObjectPosition caretPos )
  2197. {
  2198.   int       x;
  2199.   int       y;
  2200.   unsigned  width;
  2201.   unsigned  height;
  2202.   
  2203. #if DEBUG_rhess2
  2204.   fprintf (stderr,"FE_DisplayGenericCaret::[ ]\n");
  2205. #endif
  2206.  
  2207.   /*
  2208.    *    Get info extent info about the first <char_offset> characters of
  2209.    *    text.
  2210.    */
  2211.   x = image->x + image->x_offset;
  2212.   y = image->y + image->y_offset;
  2213.   width = FE_CARET_DEFAULT_WIDTH;
  2214.   height = image->line_height;
  2215.  
  2216.   if (caretPos == ED_CARET_BEFORE) {
  2217.     x -= 1;
  2218.   } else if (caretPos == ED_CARET_AFTER) {
  2219.     x += image->width;
  2220.   } else {
  2221.     width = image->width;
  2222.   }
  2223.  
  2224.   fe_caret_set(context, x, y, width, height);
  2225.   fe_caret_begin(context);
  2226. }
  2227.  
  2228. PUBLIC void
  2229. FE_DestroyCaret(MWContext * context)
  2230. {
  2231.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  2232.  
  2233. #if DEBUG_rhess2
  2234.     fprintf(stderr, "FE_DestroyCaret::[ ]\n");
  2235. #endif
  2236.  
  2237.     if (data->showing)
  2238.         fe_caret_cancel(context);
  2239.  
  2240.     data->time = 0;
  2241.     data->timer_id = 0;
  2242.     data->showing = False;
  2243.     data->running = False;
  2244.     data->backing_store = 0;
  2245. }
  2246.  
  2247. PUBLIC void
  2248. FE_ShowCaret(MWContext * context)
  2249. {
  2250. #if DEBUG_rhess2
  2251.     fprintf(stderr, "FE_ShowCaret::[ ]\n");
  2252. #endif
  2253.     fe_caret_begin(context);
  2254. }
  2255.  
  2256. /*
  2257.  *    Note all x, y co-ordinates are document relative.
  2258.  */
  2259. PUBLIC void 
  2260. FE_DocumentChanged(MWContext* context, int32 p_y, int32 p_height)
  2261. {
  2262.     int32  redraw_x = 0;
  2263.     int32  redraw_y;
  2264.     uint32 redraw_width = CONTEXT_DATA(context)->document_width;
  2265.     uint32 redraw_height;
  2266.     int32  win_y;
  2267.     uint32 win_height;
  2268.     int32  win_x;
  2269.     int32  margin_height;
  2270.     int32  margin_width;
  2271.  
  2272.     win_y = CONTEXT_DATA(context)->document_y;
  2273.     win_height = CONTEXT_DATA(context)->scrolled_height;
  2274.  
  2275.     win_x = CONTEXT_DATA(context)->document_x;
  2276.  
  2277.     /*
  2278.      *    Ok, it seems like layout doesn't take into account margins.
  2279.      *    If there was stuff in the margin before (because we *were*
  2280.      *    displaying something big, which was scrolled up), but now we
  2281.      *    are not, we must clear the margin. This code attempts
  2282.      *    to detect when we are close to the margin, and say, clear
  2283.      *    the whole thing. This seems kinda bogus, the back-end
  2284.      *    should know about margins (no?), but... djw
  2285.      */
  2286.     fe_GetMargin(context, &margin_width, &margin_height);
  2287.     
  2288.     if (p_y <= margin_height) {
  2289.         p_y = 0;
  2290.         if (p_height != -1)
  2291.             p_height += margin_height;
  2292.     }
  2293.  
  2294.     redraw_y = p_y;
  2295.  
  2296.     if (p_height < 0) {
  2297.         redraw_height = CONTEXT_DATA(context)->document_height;
  2298.         /* make sure full repaint goes to end of window at least. */
  2299.         if (win_height > redraw_height)
  2300.             redraw_height = win_height;
  2301.     } else {
  2302.         redraw_height = p_height;
  2303.     }
  2304.  
  2305.     /*
  2306.      *    Is doc change area above or below displayed region?
  2307.      */
  2308.     if (redraw_y > win_y + win_height || redraw_y + redraw_height < win_y)
  2309.         return; /* nothing to do */
  2310.  
  2311.     /*
  2312.      *    Clip redraw area.
  2313.      */
  2314.     if (redraw_y < win_y) {
  2315.         redraw_height -= (win_y - redraw_y);
  2316.         redraw_y = win_y;
  2317.     }
  2318.  
  2319.     if (redraw_y + redraw_height > win_y + win_height) {
  2320.         redraw_height = win_y + win_height - redraw_y;
  2321.     }
  2322.  
  2323.     /*FIXME*/
  2324.     /*
  2325.      *    Probably need to call CL_RefreshRegion()/Rect()
  2326.      */
  2327. #ifdef DONT_rhess
  2328.     fe_ClearArea(context, redraw_x - win_x, redraw_y - win_y,
  2329.                  redraw_width, redraw_height);
  2330. #endif
  2331.     fe_caret_cancel(context);
  2332.  
  2333.     {
  2334.         int32 ex = redraw_x;
  2335.         int32 ey = redraw_y;
  2336.         int32 ew = redraw_width;
  2337.         int32 eh = redraw_height;
  2338.  
  2339. #ifdef DEBUG_rhess2
  2340.         fprintf(stderr, "FE_DocumentChanged::[ %d, %d ][ %d, %d ]\n",
  2341.                 ex, ey, ew, eh);
  2342. #endif
  2343.         fe_RefreshArea(context, ex, ey, ew, eh);
  2344.     }
  2345. #ifdef DONT_rhess
  2346.     {
  2347.         XExposeEvent event;
  2348.  
  2349.         /* generate an expose */
  2350.         event.type = Expose;
  2351.         event.serial = 0;
  2352.         event.send_event = True;
  2353.         event.display = XtDisplay(CONTEXT_DATA(context)->drawing_area);
  2354.         event.window = XtWindow(CONTEXT_DATA(context)->drawing_area);
  2355.         event.x = redraw_x - win_x;
  2356.         event.y = redraw_y - win_y;
  2357.         event.width = redraw_width;
  2358.         event.height = redraw_height;
  2359.         event.count = 0;
  2360.         XSendEvent(event.display, event.window, False, ExposureMask, (XEvent*)&event);
  2361.     }
  2362. #endif
  2363. }
  2364.  
  2365. void FE_GetDocAndWindowPosition(MWContext * context, int32 *pX, int32 *pY, 
  2366.     int32 *pWidth, int32 *pHeight )
  2367. {
  2368.   *pX = CONTEXT_DATA (context)->document_x;
  2369.   *pY = CONTEXT_DATA (context)->document_y;
  2370.   *pWidth = CONTEXT_DATA (context)->scrolled_width;
  2371.   *pHeight = CONTEXT_DATA (context)->scrolled_height;
  2372. }
  2373.  
  2374. void
  2375. FE_SetNewDocumentProperties(MWContext* context)
  2376. {
  2377.  
  2378.     LO_Color bg_color;
  2379.     LO_Color normal_color;
  2380.     LO_Color link_color;
  2381.     LO_Color active_color;
  2382.     LO_Color followed_color;
  2383.     char background_image[MAXPATHLEN];
  2384.     XP_Bool use_custom;
  2385.     Boolean keep_images;
  2386.  
  2387.     /*
  2388.      *    Set keep images state from prefs. 
  2389.      */
  2390.     fe_EditorPreferencesGetLinksAndImages(context, NULL, &keep_images);
  2391.     fe_EditorDocumentSetImagesWithDocument(context, keep_images);
  2392.  
  2393.     /*
  2394.      *    Get editor defaults.
  2395.      */
  2396.     use_custom = fe_EditorPreferencesGetColors(context,
  2397.                                                background_image,
  2398.                                                &bg_color,
  2399.                                                &normal_color,
  2400.                                                &link_color,
  2401.                                                &active_color,
  2402.                                                &followed_color);
  2403.  
  2404.     /*
  2405.      *    Apply.
  2406.      */
  2407.     if (use_custom) {
  2408.         fe_EditorDocumentSetColors(context,
  2409.                                    background_image,
  2410.                                    FALSE,
  2411.                                    &bg_color,
  2412.                                    &normal_color,
  2413.                                    &link_color,
  2414.                                    &active_color,
  2415.                                    &followed_color);
  2416.     } else {
  2417.         fe_EditorDocumentSetColors(context,
  2418.                                    background_image, /*independent of colors*/
  2419.                                    FALSE,
  2420.                                    NULL,
  2421.                                    NULL,
  2422.                                    NULL,
  2423.                                    NULL,
  2424.                                    NULL);
  2425.     }
  2426.  
  2427.     /*
  2428.      *    Now do other stuff.
  2429.      */
  2430.     /* Title */
  2431.     fe_EditorDocumentSetTitle(context, NULL); /* will show Untitled */
  2432.  
  2433.     /* Add fixed MetaData items for author, others?? */
  2434.     fe_EditorDocumentSetMetaData(context,
  2435.                                  "Author",
  2436.                                  fe_EditorPreferencesGetAuthor(context));
  2437.     fe_EditorDocumentSetMetaData(context,
  2438.                                  "GENERATOR",
  2439.                                  "Mozilla/X");
  2440. }
  2441.  
  2442. void
  2443. fe_EditorNotifyBackgroundChanged(MWContext* context)
  2444. {
  2445. #ifdef DONT_rhess
  2446.     fe_EditorCaretData* data = &EDITOR_CONTEXT_DATA(context)->caret_data;
  2447.     
  2448.     if (data->backing_store) {
  2449.         XFreePixmap(XtDisplay(CONTEXT_DATA(context)->drawing_area),
  2450.                     data->backing_store);
  2451.         data->backing_store = 0;
  2452.     }
  2453. #endif
  2454. }
  2455.  
  2456. char* 
  2457. FE_URLToLocalName(char *name)
  2458. {
  2459.   char* qm;
  2460.   char* hm;
  2461.   char* begin;
  2462.   char* end;
  2463.   char* rv;
  2464.   char* nameSave;
  2465.   int   len;
  2466.   int   nameLen;
  2467.  
  2468.   /*
  2469.    *    Save a copy of the name as we might drop characters after '?' or '#'
  2470.    */
  2471.  
  2472.   nameLen = strlen(name);
  2473.   nameSave = XP_ALLOC(nameLen + 1);
  2474.   memcpy(nameSave, name, nameLen);
  2475.   nameSave[nameLen] = '\0';
  2476.  
  2477.   /*
  2478.    *    Drop everything after a '?' or '#' character.
  2479.    */
  2480.   qm = strchr(nameSave, '?');
  2481.   hm = strchr(nameSave, '#');
  2482.  
  2483.   if (qm && hm) {
  2484.     end = (qm > hm)? qm: hm;
  2485.   } else if (qm) {
  2486.     end = qm;
  2487.   } else if (hm) {
  2488.     end = hm;
  2489.   } else {
  2490.     end = nameSave + nameLen;
  2491.   }
  2492.  
  2493.   *end = '\0';
  2494.  
  2495.   /*
  2496.    *    Then get the basename of what's left.
  2497.    */
  2498.   if ((begin = strrchr(nameSave, '/')) != NULL && begin[1] != '\0') {
  2499.     begin++;
  2500.   } else {
  2501.     begin = nameSave;
  2502.   }
  2503.     
  2504.   len = end - begin;
  2505.   rv = malloc(len + 1);
  2506.   memcpy(rv, begin, len);
  2507.   rv[len] = '\0';
  2508.  
  2509.   XP_FREE(nameSave);
  2510.   return rv;
  2511. }
  2512.  
  2513. Boolean FE_EditorPrefConvertFileCaseOnWrite(void)
  2514. {
  2515.   fprintf (real_stderr,"FE_EditorPrefConvertFileCaseOnWrite\n");
  2516.   return TRUE;
  2517. }
  2518.  
  2519. void 
  2520. FE_FinishedSave(MWContext* context, int status,
  2521.         char *pDestURL, int iFileNumber)
  2522. {
  2523. }
  2524.  
  2525. #if 0
  2526. static void
  2527. fe_editor_copyright_hint_dialog(MWContext* context)
  2528. {
  2529.     if (!fe_globalPrefs.editor_copyright_hint)
  2530.     return;
  2531.  
  2532.     if (fe_HintDialog(context, XP_GetString(XFE_ERROR_COPYRIGHT_HINT))) {
  2533.     fe_globalPrefs.editor_copyright_hint = FALSE;
  2534.     
  2535.     /*
  2536.      *    Save options.
  2537.      */
  2538.     if (!XFE_SavePrefs((char *)fe_globalData.user_prefs_file,
  2539.                &fe_globalPrefs)) {
  2540.         fe_perror(context, XP_GetString(XFE_ERROR_SAVING_OPTIONS));
  2541.     }
  2542.     }
  2543. }
  2544. #endif
  2545.  
  2546. /*
  2547.  *    Crock timeout callback that is used by fe_EditorGetUrlExitRoutine() to
  2548.  *    kill a failed Frame (you opened a non-html doc say).
  2549.  */
  2550. static void
  2551. fe_editor_exit_timeout(XtPointer closure, XtIntervalId* id)
  2552. {
  2553.     MWContext *context = (MWContext *)closure;
  2554.  
  2555.     fe_EditorKill(context);
  2556. }
  2557.  
  2558. void
  2559. fe_EditorGetUrlExitRoutine(MWContext* context, URL_Struct* url, int status)
  2560. {
  2561.     if (status < 0) {
  2562.         /*
  2563.          *    Make sure that it's not a publish. This code is only
  2564.          *    meant for fe_GetURL() calls. Make sure the user gets to see
  2565.          *    the error dialog, then request a delete on the editor.
  2566.          */
  2567.         if (url != NULL && url->files_to_post == NULL) { /* not publish */
  2568.  
  2569.             /*
  2570.              *    Wait for popup menus to go away.
  2571.              */
  2572.             /* we need to check context->type because under certain cases we 
  2573.              * reach this loop after the editor has been killed so context is
  2574.              * garbage and if we don't check then ContextHasPopups fail
  2575.              */
  2576.             while (context && context->type == MWContextEditor && 
  2577.                    fe_ContextHasPopups(context))
  2578.                 fe_EventLoop();
  2579.         
  2580.             /*
  2581.              *    Then request a dissapearing act.
  2582.              */
  2583.             XtAppAddTimeOut(fe_XtAppContext, 0, fe_editor_exit_timeout,
  2584.                             (XtPointer)context);
  2585.         }
  2586.     }
  2587. }
  2588.  
  2589.  
  2590. /*
  2591.  * Editor calls us when we are finished loading
  2592.  * We force saving document if not editing local file
  2593.  */
  2594. void
  2595. FE_EditorDocumentLoaded(MWContext* context)
  2596. {
  2597.     History_entry* hist_ent;
  2598.     Bool           do_save_dialog;
  2599.     unsigned as_time;
  2600.     Boolean  as_enable;
  2601.     
  2602.     if (!context) {
  2603.         return;
  2604.     }
  2605.     
  2606. #ifdef DEBUG_rhess2
  2607.     fprintf(stderr, "editor::[ FE_EditorDocumentLoaded ]\n");
  2608. #endif
  2609.  
  2610.     /*
  2611.      *    Windows does a lot more gymnastics here to determine which
  2612.      *    docs should or should not be saved (especially new ones).
  2613.      *    Please look into this and match up.
  2614.      */
  2615.     /*FIXME*/
  2616.     do_save_dialog = FALSE;
  2617.     if ((hist_ent = SHIST_GetCurrent(&context->hist)) && hist_ent->address) {
  2618.         do_save_dialog = !NET_IsLocalFileURL(hist_ent->address);
  2619.     }
  2620.     
  2621. #if 0
  2622.     /*
  2623.      *    Seems we don't do this anymore.
  2624.      */
  2625.     if (!EDT_IS_NEW_DOCUMENT(context) && do_save_dialog) {
  2626.         
  2627.         /*
  2628.          *    Tongue in cheek....
  2629.          */
  2630.         fe_editor_copyright_hint_dialog(context);
  2631.     }
  2632. #endif
  2633.     
  2634. #ifdef MOZ_MAIL_NEWS
  2635.     if (context->type == MWContextMessageComposition) {
  2636.         fe_MailComposeDocumentLoaded(context);
  2637.     }
  2638.     else 
  2639. #endif
  2640.         xfe2_EditorInit(context);
  2641.     
  2642.     /*
  2643.      *    Set autosave period.
  2644.      */
  2645.     fe_EditorPreferencesGetAutoSave(context, &as_enable, &as_time);
  2646.     EDT_SetAutoSavePeriod(context, as_time);
  2647.     
  2648.     fe_HackEditorNotifyToolbarUpdated(context);
  2649. }
  2650.  
  2651. static char fe_SaveDialogSaveName[] = "saveMessageDialog";
  2652. static char fe_SaveDialogUploadName[] = "uploadMessageDialog";
  2653. static char fe_SaveDialogPrepareName[] = "prepareMessageDialog";
  2654. static char fe_SaveDialogImageLoadName[] = "imageLoadMessageDialog";
  2655.  
  2656. typedef enum fe_SaveDialogType
  2657. {
  2658.     XFE_SAVE_DIALOG_SAVE,
  2659.     XFE_SAVE_DIALOG_UPLOAD,
  2660.     XFE_SAVE_DIALOG_PREPARE,
  2661.     XFE_SAVE_DIALOG_IMAGELOAD
  2662. } fe_SaveDialogType;
  2663.  
  2664. typedef struct fe_SaveDialogInfo
  2665. {
  2666.     unsigned          nfiles;
  2667.     unsigned          current;
  2668.     fe_SaveDialogType type;
  2669. } fe_SaveDialogInfo;
  2670.  
  2671. static void
  2672. fe_save_dialog_info_init(Widget msg_box, fe_SaveDialogType type, unsigned n)
  2673. {
  2674.     fe_SaveDialogInfo* info = (fe_SaveDialogInfo*)XtNew(fe_SaveDialogInfo);
  2675.     
  2676.     if (info == NULL)
  2677.     return;
  2678.  
  2679.     info->nfiles = n;
  2680.     info->type = type;
  2681.     info->current = 0;
  2682.  
  2683.     XtVaSetValues(msg_box, XmNuserData, (XtPointer)info, 0);
  2684. }
  2685.  
  2686. #define XFE_SAVE_DIALOG_NEXT (-1)
  2687.  
  2688. static void
  2689. fe_save_dialog_info_set(Widget msg_box, char* filename, int index)
  2690. {
  2691.     XtPointer          user_data;
  2692.     fe_SaveDialogInfo* info;
  2693.     char               buf[MAXPATHLEN];
  2694.     int                id;
  2695.     char*              string;
  2696.     XmString           xm_string;
  2697.  
  2698.     XtVaGetValues(msg_box, XmNuserData, &user_data, 0);
  2699.     if (user_data != 0) {
  2700.     info = (fe_SaveDialogInfo*)user_data;
  2701.  
  2702.     if (index == XFE_SAVE_DIALOG_NEXT)
  2703.         info->current++;
  2704.     else
  2705.         info->current = index;
  2706.  
  2707.     if (info->current > info->nfiles)
  2708.         info->nfiles = info->current;
  2709.  
  2710.     switch (info->type) {
  2711.     case XFE_SAVE_DIALOG_IMAGELOAD:
  2712.         id = XFE_LOADING_IMAGE_FILE;
  2713.         break;
  2714.     case XFE_SAVE_DIALOG_UPLOAD:
  2715.         id = XFE_UPLOADING_FILE;
  2716.         break;
  2717.     case XFE_SAVE_DIALOG_PREPARE:
  2718.         id = XFE_PREPARE_UPLOAD;
  2719.         break;
  2720.     default:
  2721.         id = XFE_SAVING_FILE;
  2722.         break;
  2723.     }
  2724.  
  2725.     string = XP_GetString(id);
  2726.  
  2727.     if (!filename)
  2728.         filename = "";
  2729.     sprintf(buf, string, filename);
  2730.     
  2731.     if (info->nfiles > 1) {
  2732.         strcat(buf, "\n");
  2733.         string = XP_GetString(XFE_FILE_N_OF_N);
  2734.         sprintf(&buf[strlen(buf)], string, info->current, info->nfiles);
  2735.     }
  2736.     
  2737.     xm_string = XmStringCreateLocalized(buf);
  2738.     } else {
  2739.     xm_string = XmStringCreateLocalized(filename);
  2740.     }
  2741.     XtVaSetValues(msg_box, XmNmessageString, xm_string, 0);
  2742.     XmStringFree(xm_string);
  2743. }
  2744.  
  2745. static fe_SaveDialogType
  2746. fe_SaveDialogGetType(Widget msg_box)
  2747. {
  2748.     char* name = XtName(msg_box);
  2749.  
  2750.     if (strcmp(name, fe_SaveDialogSaveName) == 0)
  2751.         return XFE_SAVE_DIALOG_SAVE;
  2752.     else if (strcmp(name, fe_SaveDialogUploadName) == 0)
  2753.         return XFE_SAVE_DIALOG_UPLOAD;
  2754.     else if (strcmp(name, fe_SaveDialogPrepareName) == 0)
  2755.         return XFE_SAVE_DIALOG_PREPARE;
  2756.     else
  2757.         return XFE_SAVE_DIALOG_IMAGELOAD;
  2758. }
  2759.  
  2760. static void
  2761. fe_save_dialog_cancel_cb(Widget msg_box, XtPointer closure, XtPointer cb_data)
  2762. {
  2763.     MWContext* context = (MWContext*)closure;
  2764.  
  2765.     if (fe_SaveDialogGetType(msg_box) == XFE_SAVE_DIALOG_SAVE) {
  2766.         EDT_SaveCancel(context);
  2767.     } else {
  2768.         NET_InterruptWindow(context);
  2769.     }
  2770. }
  2771.  
  2772. static void
  2773. fe_save_dialog_destroy_cb(Widget msg_box, XtPointer closure, XtPointer cb_data)
  2774. {
  2775.     MWContext* context = (MWContext*)closure;
  2776.     XtPointer  user_data;
  2777.     
  2778.     if (CONTEXT_DATA(context)->posted_msg_box == msg_box)
  2779.         CONTEXT_DATA(context)->posted_msg_box = NULL;
  2780.  
  2781.     XtVaGetValues(msg_box, XmNuserData, &user_data, 0);
  2782.     if (user_data != NULL)
  2783.         XtFree(user_data);
  2784. }
  2785.  
  2786. static Widget
  2787. fe_save_dialog_create(MWContext* context, char* name)
  2788. {
  2789.     Widget mainw = CONTEXT_WIDGET(context);
  2790.     Widget msg_box;
  2791.     Visual *v = 0;
  2792.     Colormap cmap = 0;
  2793.     Cardinal depth = 0;
  2794.     Arg args [20];
  2795.     Cardinal n;
  2796.  
  2797.     if (CONTEXT_DATA(context)->posted_msg_box != NULL)
  2798.     return CONTEXT_DATA(context)->posted_msg_box;
  2799.  
  2800.     XtVaGetValues(mainw, XtNvisual, &v, XtNcolormap, &cmap,
  2801.           XtNdepth, &depth, 0);
  2802.  
  2803.     n = 0;
  2804.     XtSetArg(args[n], XmNvisual, v); n++;
  2805.     XtSetArg(args[n], XmNdepth, depth); n++;
  2806.     XtSetArg(args[n], XmNcolormap, cmap); n++;
  2807.     XtSetArg(args[n], XmNallowShellResize, TRUE); n++;
  2808.     XtSetArg(args[n], XmNtransientFor, mainw); n++;
  2809.     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
  2810.     XtSetArg(args[n], XmNdialogType, XmDIALOG_MESSAGE); n++;
  2811.     XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++;
  2812.     XtSetArg(args[n], XmNautoUnmanage, FALSE); n++;
  2813.     XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
  2814.  
  2815.     msg_box = XmCreateMessageDialog(mainw, name, args, n);
  2816.  
  2817.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msg_box, XmDIALOG_OK_BUTTON));
  2818.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msg_box, XmDIALOG_HELP_BUTTON));
  2819.  
  2820.     XtAddCallback(msg_box, XmNcancelCallback, fe_save_dialog_cancel_cb,
  2821.           (XtPointer)context);
  2822.     XtAddCallback(msg_box, XmNdestroyCallback, fe_save_dialog_destroy_cb,
  2823.           (XtPointer)context);
  2824.  
  2825.     CONTEXT_DATA(context)->posted_msg_box = msg_box;
  2826.  
  2827.     return msg_box;
  2828. }
  2829.  
  2830. static void
  2831. fe_destroy_parent_cb(Widget widget, XtPointer closure, XtPointer cbd)
  2832. {
  2833.     XtDestroyWidget(XtParent(widget));
  2834. }
  2835.  
  2836. static void 
  2837. fe_save_dialog_destroy(Widget msg_box)
  2838. {
  2839.     Widget   shell = XtParent(msg_box);
  2840.     Cardinal num_popups = XfeNumPopups(shell);
  2841.     Widget*  popups = XfePopupList(shell);
  2842.  
  2843.     /*
  2844.      *    If we have a stacked popup on us, them wait for that
  2845.      *    popup to destroy before we destroy ourselves. Do this by
  2846.      *    setting a destroy callback on the popup that destroys
  2847.      *    it's parent (us). Amongst other things we need to do this
  2848.      *    because server side error messages get stacked on the save
  2849.      *    progress dialog.
  2850.      */
  2851.     if (num_popups > 0) { /* anyone who adds to me after this is a loser */
  2852.         XtAddCallback(popups[0], XmNdestroyCallback, fe_destroy_parent_cb, 0);
  2853.     } else {
  2854.         XtDestroyWidget(msg_box);
  2855.     }
  2856. }
  2857.  
  2858. /*
  2859.  *    Dialog to give feedback and allow canceling, overwrite protection
  2860.  *    when downloading remote files 
  2861.  *
  2862.  *    put up a save dialog that says "i'm saving foo right now", cancel?
  2863.  *    and return right away. 
  2864.  */
  2865. void 
  2866. FE_SaveDialogCreate(MWContext* context, int nfiles, ED_SaveDialogType saveType)
  2867. {
  2868.     Widget msg_box;
  2869.     char*  name;
  2870.     fe_SaveDialogType type;
  2871.  
  2872.     if (CONTEXT_DATA(context)->posted_msg_box != NULL)
  2873.         return;
  2874.  
  2875.     switch (saveType) {
  2876.     case ED_SAVE_DLG_PUBLISH:
  2877.         name = fe_SaveDialogUploadName;
  2878.         type = XFE_SAVE_DIALOG_UPLOAD;
  2879.         break;
  2880.     case ED_SAVE_DLG_PREPARE_PUBLISH:
  2881.         name = fe_SaveDialogPrepareName;
  2882.         type = XFE_SAVE_DIALOG_PREPARE;
  2883.         break;
  2884.     default:
  2885.         name = fe_SaveDialogSaveName;
  2886.         type = XFE_SAVE_DIALOG_SAVE;
  2887.         break;
  2888.     }
  2889.  
  2890.     msg_box = fe_save_dialog_create(context, name);
  2891.  
  2892.     fe_save_dialog_info_init(msg_box, type, nfiles);
  2893.  
  2894.     CONTEXT_DATA(context)->posted_msg_box = msg_box;
  2895.  
  2896.     /* this is here so that we know when the file saying is over */
  2897.     CONTEXT_DATA(context)->is_file_saving = True;
  2898.  
  2899.     /*
  2900.      *    Postpone until we have something to say..
  2901.     XtManageChild(msg_box);
  2902.      */
  2903. }
  2904.  
  2905. void 
  2906. FE_SaveDialogSetFilename(MWContext* context, char* filename) 
  2907. {
  2908.     Widget msg_box = CONTEXT_DATA(context)->posted_msg_box;
  2909.     
  2910.     if (!msg_box)
  2911.         return;
  2912.     
  2913.     fe_save_dialog_info_set(msg_box, filename, XFE_SAVE_DIALOG_NEXT);
  2914.     
  2915.     if (!XtIsManaged(msg_box))
  2916.         XtManageChild(msg_box);
  2917.  
  2918.     XfeUpdateDisplay(msg_box);
  2919. }
  2920.  
  2921. void 
  2922. FE_SaveDialogDestroy(MWContext* context, int status, char* file_url)
  2923. {
  2924.     Widget msg_box = CONTEXT_DATA(context)->posted_msg_box;
  2925.     fe_SaveDialogType type;
  2926.     
  2927.     if (msg_box == NULL)
  2928.         return;
  2929.  
  2930.     type = fe_SaveDialogGetType(msg_box);
  2931.  
  2932.     if (type == XFE_SAVE_DIALOG_SAVE) {
  2933.         CONTEXT_DATA(context)->save_file_url = file_url;
  2934.         CONTEXT_DATA(context)->file_save_status = status;
  2935.     }
  2936.     
  2937.     fe_save_dialog_destroy(msg_box);
  2938.     CONTEXT_DATA(context)->posted_msg_box = NULL;
  2939.     /* this is here so that we know when the file saying is over */
  2940.     CONTEXT_DATA(context)->is_file_saving = False;
  2941. }
  2942.  
  2943. void
  2944. FE_ImageLoadDialog(MWContext* context)
  2945. {
  2946.     Widget msg_box;
  2947.  
  2948.     if (CONTEXT_DATA(context)->posted_msg_box != NULL)
  2949.     return;
  2950.  
  2951.     msg_box = fe_save_dialog_create(context, fe_SaveDialogImageLoadName);
  2952.  
  2953.     fe_save_dialog_info_init(msg_box, XFE_SAVE_DIALOG_IMAGELOAD, 1);
  2954.     CONTEXT_DATA(context)->posted_msg_box = msg_box;
  2955.  
  2956.     fe_save_dialog_info_set(msg_box, "", 1);
  2957.  
  2958.     XtManageChild(msg_box);
  2959. }
  2960.  
  2961. void
  2962. FE_ImageLoadDialogDestroy(MWContext* context)
  2963. {
  2964.     Widget msg_box = CONTEXT_DATA(context)->posted_msg_box;
  2965.  
  2966.     if (msg_box == NULL)
  2967.     return;
  2968.  
  2969.     fe_save_dialog_destroy(msg_box);
  2970.  
  2971.     CONTEXT_DATA(context)->posted_msg_box = NULL;
  2972. }
  2973.  
  2974. typedef struct {
  2975.   Widget  form;
  2976.   Widget  widget;
  2977.   unsigned response;
  2978.   Boolean done;
  2979. } YesToAllInfo;
  2980.  
  2981. static void
  2982. fe_yes_to_all_cb(Widget widget, XtPointer closure, XtPointer call_data)
  2983. {
  2984.   YesToAllInfo* info = (YesToAllInfo*)closure;
  2985.   int i;
  2986.   char* name;
  2987.   char* widget_name = XtName(widget);
  2988.  
  2989.   for (i = 0; (name = fe_CreateYesToAllDialog_button_data[i].name); i++) {
  2990.     if (strcmp(name, widget_name) == 0) {
  2991.       info->response = fe_CreateYesToAllDialog_button_data[i].type;
  2992.       break;
  2993.     }
  2994.   }
  2995.  
  2996.   info->widget = widget;
  2997.   info->done = TRUE;
  2998.  
  2999.   XtUnmanageChild(info->form);
  3000. }
  3001.  
  3002. #if 0
  3003. static unsigned
  3004. fe_OverWriteFileQuestionDialog(MWContext* context, char* filename)
  3005. {
  3006.   char* msg;
  3007.   int   size;
  3008.   Bool  rv = FALSE;
  3009.  
  3010.   size = XP_STRLEN(filename) + 1 /* slash*/
  3011.        + XP_STRLEN(fe_globalData.overwrite_file_message) + 1; /*nul*/
  3012.  
  3013.   msg = (char *)XP_ALLOC(size);
  3014.   if (!msg)
  3015.     return False;
  3016.  
  3017.   PR_snprintf(msg, size, fe_globalData.overwrite_file_message, filename);
  3018.  
  3019.   if (FE_Confirm(context, msg))
  3020.     rv = TRUE;
  3021.  
  3022.   XP_FREE(msg);
  3023.  
  3024.   return rv;
  3025. }
  3026. #endif
  3027.  
  3028. static unsigned
  3029. fe_DoYesToAllDialog(MWContext* context, char* filename)
  3030. {
  3031.   YesToAllInfo info;
  3032.   Arg      av[20];
  3033.   Cardinal ac;
  3034.   XtCallbackRec cb_data;
  3035.   XmString msg_string;
  3036.   char* msg;
  3037.   int size;
  3038.   Widget form;
  3039.   Widget default_button;
  3040.  
  3041.   size = XP_STRLEN(filename) + 1 /* slash*/
  3042.        + XP_STRLEN(fe_globalData.overwrite_file_message) + 1; /*nul*/
  3043.  
  3044.   msg = (char *)XP_ALLOC(size);
  3045.   if (!msg)
  3046.     return XFE_DIALOG_CANCEL_BUTTON;
  3047.  
  3048.   PR_snprintf(msg, size, fe_globalData.overwrite_file_message, filename);
  3049.   msg_string = XmStringCreateLocalized(msg);
  3050.   XP_FREE(msg);
  3051.  
  3052.   cb_data.callback = fe_yes_to_all_cb;
  3053. #ifdef OSF1
  3054.   cb_data.closure = (void *)&info;
  3055. #else
  3056.   cb_data.closure = &info;
  3057. #endif
  3058.  
  3059.   ac = 0;
  3060.   XtSetArg(av[ac], XmNarmCallback, &cb_data); ac++;
  3061.   XtSetArg(av[ac], XmNmessageString, msg_string); ac++;
  3062.   form = fe_CreateYesToAllDialog(context, "confirmSaveFiles", av, ac);
  3063.  
  3064.   default_button = fe_YesToAllDialogGetChild(form, XFE_DAILOG_YESTOALL_BUTTON);
  3065.   ac = 0;
  3066.   XtSetArg(av[ac], XmNdefaultButton, default_button); ac++;
  3067. #if 0 /* why doesn't this work? */
  3068.   XtSetArg(av[ac], XmNinitialFocus, default_button); ac++;
  3069. #endif
  3070.   XtSetValues(form, av, ac);
  3071.  
  3072.   info.response = XFE_DIALOG_CANCEL_BUTTON;
  3073.   info.done = FALSE;
  3074.   info.widget = NULL;
  3075.   info.form = form;
  3076.  
  3077.   XmStringFree(msg_string);
  3078.     
  3079.   XtManageChild(form);
  3080.  
  3081.   fe_NukeBackingStore(form);
  3082.   while (!info.done)
  3083.     fe_EventLoop();
  3084.  
  3085.   XtDestroyWidget(form);
  3086.  
  3087.   return info.response;
  3088. }
  3089.  
  3090. ED_SaveOption
  3091. FE_SaveFileExistsDialog(MWContext* context, char* filename) 
  3092. {
  3093.   switch (fe_DoYesToAllDialog(context, filename)) {
  3094.   case XFE_DIALOG_YES_BUTTON:
  3095.     return ED_SAVE_OVERWRITE_THIS;
  3096.   case XFE_DAILOG_YESTOALL_BUTTON:
  3097.     return ED_SAVE_OVERWRITE_ALL;
  3098.   case XFE_DIALOG_NO_BUTTON:
  3099.     return ED_SAVE_DONT_OVERWRITE_THIS;
  3100.   case XFE_DIALOG_NOTOALL_BUTTON:
  3101.     return ED_SAVE_DONT_OVERWRITE_ALL;
  3102.   default:
  3103.     return ED_SAVE_CANCEL;
  3104.   }
  3105. }
  3106.  
  3107. Boolean
  3108. FE_SaveErrorContinueDialog(MWContext*   context,
  3109.                char*        filename, 
  3110.                ED_FileError error)
  3111. {
  3112.   if (error != ED_ERROR_NONE) {
  3113.       /* There was a an error while saving on:\n%s */
  3114.       /* The error code = (%d).*/
  3115.       return fe_editor_report_file_error(context, error, filename, TRUE);
  3116.   } else {
  3117.       return TRUE;
  3118.   }
  3119. }
  3120.  
  3121. Boolean XP_ConvertUrlToLocalFile (const char *url, char **localName)
  3122. {
  3123.   Boolean filefound = FALSE;
  3124.   char *path = NULL;
  3125.   char *file = NULL;
  3126.   XP_StatStruct statinfo;
  3127.  
  3128.   if (localName)
  3129.     {
  3130.       *localName = NULL;
  3131.     }
  3132.  
  3133.   /* Must have "file:" url type and at least 1 character after '//' */
  3134.   if (!url || !NET_IsLocalFileURL((char *) url))
  3135.     {
  3136.     return FALSE; 
  3137.     }
  3138.  
  3139.   /* Extract file path from url: e.g. "/cl/foo/file.html" */
  3140.   path = NET_ParseURL (url, GET_PATH_PART);
  3141.   if (!path || XP_STRLEN(path) < 1) {
  3142.     return FALSE;
  3143.   }
  3144.  
  3145. #if 0
  3146.   /* Get filename - skip over initial "/" */
  3147.   file = WH_FileName (path+1, xpURL);
  3148.   XP_FREE (path);
  3149. #endif
  3150.   file = XP_STRDUP(path);
  3151.  
  3152.   /* Test if file exists */
  3153.   if (XP_Stat (file, &statinfo, xpURL) >= 0 &&
  3154.       statinfo.st_mode & S_IFREG)
  3155.     {
  3156.       filefound = TRUE;
  3157.     }
  3158.  
  3159.   if (localName)
  3160.     {
  3161.       /* Pass string to caller; we didn't change it, so there's
  3162.          no need to strdup
  3163.          */
  3164.       *localName = file;
  3165.     }
  3166.  
  3167.   return filefound;
  3168. }
  3169.  
  3170. char *
  3171. XP_BackupFileName (const char *url)
  3172. {
  3173.   char *filename = NULL;
  3174.   char* path;
  3175.  
  3176.   /* Must have a "file:" url and at least 1 character after the "//" */
  3177.   if (!url || !NET_IsLocalFileURL((char *) url))
  3178.     {
  3179.       return FALSE;
  3180.     }
  3181.  
  3182.   /* Extract file path from url: e.g. "/cl/foo/file.html" */
  3183.   path = NET_ParseURL (url, GET_PATH_PART);
  3184.   if (!path || XP_STRLEN(path) < 1) {
  3185.     return FALSE;
  3186.   }
  3187.  
  3188.   filename = (char *) XP_ALLOC ((XP_STRLEN (path) + 5) * sizeof (char));
  3189.   if (!filename)
  3190.     {
  3191.       return NULL;
  3192.     }
  3193.  
  3194.   /* Get filename but ignore "file://" */
  3195.   {
  3196.       char* filename2 = WH_FileName (path, xpURL);
  3197.       if (!filename2) return NULL;
  3198.       XP_STRCPY (filename, filename2);
  3199.       XP_FREE(filename2);
  3200.   }
  3201.  
  3202.   /* Add extension to the filename */
  3203.   XP_STRCAT (filename, "~");
  3204.   return filename;
  3205. }
  3206.  
  3207. void
  3208. fe_EditorUpdateToolbar(MWEditorContext* context, ED_TextFormat unused_for_now)
  3209. {
  3210. }
  3211.  
  3212. Boolean
  3213. fe_EditorLineBreakCanInsert(MWContext* context)
  3214. {
  3215.    return (EDT_IsSelected(context) == FALSE);
  3216. }
  3217.  
  3218. /*
  3219.  *    type             description
  3220.  *    ED_BREAK_NORMAL  insert line break, ignore images.
  3221.  *    ED_BREAK_LEFT    Break so it passes the image on the left
  3222.  *    ED_BREAK_RIGHT   Break past the right image.
  3223.  *    ED_BREAK_BOTH    Break below image(s).
  3224.  */
  3225. void
  3226. fe_EditorLineBreak(MWContext* context, ED_BreakType type)
  3227. {
  3228.     if (!fe_EditorLineBreakCanInsert(context))
  3229.         return;
  3230.     EDT_InsertBreak(context, type);
  3231.     fe_EditorUpdateToolbar(context, 0);
  3232. }
  3233.  
  3234. void
  3235. fe_EditorNonBreakingSpace(MWContext* context)
  3236. {
  3237.     EDT_InsertNonbreakingSpace(context);
  3238.     fe_EditorUpdateToolbar(context, 0);
  3239. }
  3240.  
  3241. void
  3242. fe_EditorParagraphMarksSetState(MWContext* context, Boolean display)
  3243. {
  3244.     EDT_SetDisplayParagraphMarks(context, (Bool)display);
  3245. }
  3246.  
  3247. Boolean
  3248. fe_EditorParagraphMarksGetState(MWContext* context)
  3249. {
  3250.     return (Boolean)EDT_GetDisplayParagraphMarks(context);
  3251. }
  3252.  
  3253. char*
  3254. fe_EditorDefaultGetTemplate()
  3255. {
  3256.     return XFE_EDITOR_DEFAULT_DOCUMENT_TEMPLATE_URL;
  3257. }
  3258.  
  3259. void
  3260. fe_EditorDefaultGetColors(LO_Color*  bg_color,
  3261.               LO_Color*  normal_color,
  3262.               LO_Color*  link_color,
  3263.               LO_Color*  active_color,
  3264.               LO_Color*  followed_color)
  3265. {
  3266.     if (bg_color)
  3267.         *bg_color = lo_master_colors[LO_COLOR_BG];
  3268.  
  3269.     if (normal_color)
  3270.         *normal_color = lo_master_colors[LO_COLOR_FG];
  3271.  
  3272.     if (link_color)
  3273.         *link_color = lo_master_colors[LO_COLOR_LINK];
  3274.  
  3275.     if (active_color)
  3276.         *active_color = lo_master_colors[LO_COLOR_ALINK];
  3277.  
  3278.     if (followed_color)
  3279.         *followed_color = lo_master_colors[LO_COLOR_VLINK];
  3280. }
  3281.  
  3282. static char* fe_last_publish_location;
  3283. static char* fe_last_publish_username;
  3284. static char* fe_last_publish_password;
  3285.  
  3286. #define SAFE_STRDUP(x) ((x)? XP_STRDUP(x): NULL)
  3287.  
  3288. Boolean
  3289. fe_EditorDefaultGetLastPublishLocation(MWContext* context,
  3290.                        char** location,
  3291.                        char** username,
  3292.                        char** password)
  3293. {
  3294.     if (location)
  3295.         *location = SAFE_STRDUP(fe_last_publish_location);
  3296.     if (username)
  3297.         *username = SAFE_STRDUP(fe_last_publish_username);
  3298.     if (password)
  3299.         *password = SECNAV_UnMungeString(fe_last_publish_password);
  3300.  
  3301.     return fe_last_publish_password != NULL;
  3302. }
  3303.  
  3304. void
  3305. fe_EditorDefaultSetLastPublishLocation(MWContext* context,
  3306.                        char* location,
  3307.                        char* username,
  3308.                        char* password)
  3309. {
  3310.     /* NOTE: this function is not MT safe */
  3311.     if (fe_last_publish_location)
  3312.         XP_FREE(fe_last_publish_location);
  3313.     if (fe_last_publish_username)
  3314.         XP_FREE(fe_last_publish_username);
  3315.     if (fe_last_publish_password)
  3316.         XP_FREE(fe_last_publish_password);
  3317.  
  3318.     fe_last_publish_location = NULL;
  3319.     fe_last_publish_username = NULL;
  3320.     fe_last_publish_password = NULL;
  3321.  
  3322.     if (location) {
  3323.         char* full_location;
  3324.         int   rv;
  3325.  
  3326.         fe_last_publish_location = XP_STRDUP(location);
  3327.  
  3328.         if (username)
  3329.             fe_last_publish_username = XP_STRDUP(username);
  3330.  
  3331.         if (password)
  3332.             fe_last_publish_password = SECNAV_MungeString(password);
  3333.  
  3334.         full_location = NULL; /* having to do this is SO stupid */
  3335.         rv = NET_MakeUploadURL(&full_location, location, username, NULL);
  3336.  
  3337.         if (rv && full_location != NULL) {
  3338.             PREF_SetCharPref("editor.publish_last_loc", full_location);
  3339.             PREF_SetCharPref("editor.publish_last_pass",
  3340.                              fe_last_publish_password?
  3341.                              fe_last_publish_password: "");
  3342.         }
  3343.     }
  3344. }
  3345.  
  3346. void
  3347. fe_EditorPreferencesGetAutoSave(MWContext* context,
  3348.                 Boolean*   enable,
  3349.                 unsigned*  time)
  3350. {
  3351.     if (fe_globalPrefs.editor_autosave_period == 0) {
  3352.     *time = 0;
  3353.     *enable = FALSE;
  3354.     } else {
  3355.     *time = fe_globalPrefs.editor_autosave_period;
  3356.     *enable = TRUE;
  3357.     }
  3358. }
  3359.  
  3360. void
  3361. fe_EditorPreferencesSetAutoSave(MWContext* context,
  3362.                 Boolean    enable,
  3363.                 unsigned   time)
  3364. {
  3365.     struct fe_MWContext_cons *rest;
  3366.  
  3367.     if (enable) {
  3368.     fe_globalPrefs.editor_autosave_period = time;
  3369.     } else {
  3370.     fe_globalPrefs.editor_autosave_period = 0;
  3371.     time = 0;
  3372.     }
  3373.  
  3374.     /*
  3375.      *    Walk over the contexts, and tell the BE to reset the
  3376.      *    autosave.
  3377.      */
  3378.     for (rest = fe_all_MWContexts; rest; rest = rest->next) {
  3379.     if (rest->context->type == MWContextEditor) {
  3380.         EDT_SetAutoSavePeriod(rest->context, time);
  3381.     }
  3382.     }
  3383. }
  3384.  
  3385. void
  3386. fe_EditorPreferencesGetLinksAndImages(MWContext* context,
  3387.                       Boolean*   links, 
  3388.                       Boolean*   images)
  3389. {
  3390.     if (links)
  3391.     *links = fe_globalPrefs.editor_maintain_links;
  3392.     if (images)
  3393.     *images = fe_globalPrefs.editor_keep_images;
  3394. }
  3395.  
  3396. void
  3397. fe_EditorPreferencesSetLinksAndImages(MWContext* context,
  3398.                       Boolean    links, 
  3399.                       Boolean    images)
  3400. {
  3401.     fe_globalPrefs.editor_maintain_links = links;
  3402.     fe_globalPrefs.editor_keep_images = images;
  3403. }
  3404.  
  3405. Boolean
  3406. fe_EditorPreferencesGetPublishLocation(MWContext* context,
  3407.                        char** location,
  3408.                        char** username,
  3409.                        char** password)
  3410. {
  3411.     if (location)
  3412.         *location = SAFE_STRDUP(fe_globalPrefs.editor_publish_location);
  3413.     if (username)
  3414.         *username = SAFE_STRDUP(fe_globalPrefs.editor_publish_username);
  3415.     if (password)
  3416.         *password =
  3417.       SECNAV_UnMungeString(fe_globalPrefs.editor_publish_password);
  3418.  
  3419.     return (fe_globalPrefs.editor_publish_password != NULL);
  3420. }
  3421.  
  3422. void
  3423. fe_EditorPreferencesSetPublishLocation(MWContext* context,
  3424.                        char* location,
  3425.                        char* username,
  3426.                        char* password)
  3427. {
  3428.     if (fe_globalPrefs.editor_publish_location)
  3429.         XP_FREE(fe_globalPrefs.editor_publish_location);
  3430.     if (fe_globalPrefs.editor_publish_username)
  3431.         XP_FREE(fe_globalPrefs.editor_publish_username);
  3432.     if (fe_globalPrefs.editor_publish_password)
  3433.         XP_FREE(fe_globalPrefs.editor_publish_password);
  3434.  
  3435.     fe_globalPrefs.editor_publish_location = NULL;
  3436.     fe_globalPrefs.editor_publish_username = NULL;
  3437.     fe_globalPrefs.editor_publish_password = NULL;
  3438.  
  3439.     if (location) {
  3440.         fe_globalPrefs.editor_publish_location = XP_STRDUP(location);
  3441.  
  3442.     if (username)
  3443.         fe_globalPrefs.editor_publish_username = XP_STRDUP(username);
  3444.  
  3445.     if (password)
  3446.         fe_globalPrefs.editor_publish_password
  3447.           = SECNAV_MungeString(password);
  3448.     }
  3449.     fe_globalPrefs.editor_save_publish_password = (password != NULL);
  3450. }
  3451.  
  3452. char*
  3453. fe_EditorPreferencesGetBrowseLocation(MWContext* context)
  3454. {
  3455.     return SAFE_STRDUP(fe_globalPrefs.editor_browse_location);
  3456. }
  3457.  
  3458. void
  3459. fe_EditorPreferencesSetBrowseLocation(MWContext* context, char* location)
  3460. {
  3461.     if (fe_globalPrefs.editor_browse_location)
  3462.         XP_FREE(fe_globalPrefs.editor_browse_location);
  3463.     fe_globalPrefs.editor_browse_location = NULL;
  3464.  
  3465.     if (location)
  3466.     fe_globalPrefs.editor_browse_location = XP_STRDUP(location);
  3467. }
  3468.  
  3469. char*
  3470. fe_EditorPreferencesGetAuthor(MWContext* context)
  3471. {
  3472.     if (fe_globalPrefs.editor_author_name)
  3473.     return fe_globalPrefs.editor_author_name;
  3474.     else
  3475.     return "";
  3476. }
  3477.  
  3478. void
  3479. fe_EditorPreferencesSetAuthor(MWContext* context, char* name)
  3480. {
  3481.     if (fe_globalPrefs.editor_author_name)
  3482.     XtFree(fe_globalPrefs.editor_author_name);
  3483.     fe_globalPrefs.editor_author_name = XtNewString(name);
  3484. }
  3485.  
  3486. char*
  3487. fe_EditorPreferencesGetTemplate(MWContext* context)
  3488. {
  3489.     if (fe_globalPrefs.editor_document_template)
  3490.     return fe_globalPrefs.editor_document_template;
  3491.     else
  3492.     return NULL;
  3493. }
  3494.  
  3495. void
  3496. fe_EditorPreferencesSetTemplate(MWContext* context, char* name)
  3497. {
  3498.     if (fe_globalPrefs.editor_document_template)
  3499.     XtFree(fe_globalPrefs.editor_document_template);
  3500.     fe_globalPrefs.editor_document_template = XtNewString(name);
  3501. }
  3502.  
  3503. void
  3504. fe_EditorPreferencesGetEditors(MWContext* context, char** html, char** image)
  3505. {
  3506.     if (html != NULL) {
  3507.     if (fe_globalPrefs.editor_html_editor)
  3508.         *html = fe_globalPrefs.editor_html_editor;
  3509.     else
  3510.         *html = NULL;
  3511.     }
  3512.  
  3513.     if (image != NULL) {
  3514.     if (fe_globalPrefs.editor_image_editor)
  3515.         *image = fe_globalPrefs.editor_image_editor;
  3516.     else
  3517.         *image = NULL;
  3518.     }
  3519. }
  3520.  
  3521. void
  3522. fe_EditorPreferencesSetEditors(MWContext* context, char* html, char* image)
  3523. {
  3524.     if (html != NULL) {
  3525.     if (fe_globalPrefs.editor_html_editor)
  3526.         XtFree(fe_globalPrefs.editor_html_editor);
  3527.     fe_globalPrefs.editor_html_editor = XtNewString(html);
  3528.     }
  3529.  
  3530.     if (image != NULL) {
  3531.     if (fe_globalPrefs.editor_image_editor)
  3532.         XtFree(fe_globalPrefs.editor_image_editor);
  3533.     fe_globalPrefs.editor_image_editor = XtNewString(image);
  3534.     }
  3535. }
  3536.  
  3537. Boolean
  3538. fe_EditorPreferencesGetColors(MWContext* context,
  3539.                   char*      background_image,
  3540.                   LO_Color*  bg_color,
  3541.                   LO_Color*  normal_color,
  3542.                   LO_Color*  link_color,
  3543.                   LO_Color*  active_color,
  3544.                   LO_Color*  followed_color)
  3545. {
  3546.     if (bg_color)
  3547.     *bg_color = fe_globalPrefs.editor_background_color;
  3548.     if (normal_color)
  3549.     *normal_color = fe_globalPrefs.editor_normal_color;
  3550.     if (link_color)
  3551.     *link_color = fe_globalPrefs.editor_link_color;
  3552.     if (active_color)
  3553.     *active_color = fe_globalPrefs.editor_active_color;
  3554.     if (followed_color)
  3555.     *followed_color = fe_globalPrefs.editor_followed_color;
  3556.  
  3557.     if (background_image) {
  3558.     if (fe_globalPrefs.editor_background_image)
  3559.         strcpy(background_image,  fe_globalPrefs.editor_background_image);
  3560.     else
  3561.         background_image[0] = '\0';
  3562.     }
  3563.  
  3564.     return fe_globalPrefs.editor_custom_colors;
  3565. }
  3566.  
  3567. void
  3568. fe_EditorPreferencesSetColors(MWContext* context,
  3569.                               char*      background_image,
  3570.                               LO_Color*  bg_color,
  3571.                               LO_Color*  normal_color,
  3572.                               LO_Color*  link_color,
  3573.                               LO_Color*  active_color,
  3574.                               LO_Color*  followed_color)
  3575. {
  3576.     XP_Bool set = FALSE;
  3577.  
  3578.     if (bg_color) {
  3579.         fe_globalPrefs.editor_background_color = *bg_color;
  3580.         set = TRUE;
  3581.     }
  3582.     if (normal_color) {
  3583.         fe_globalPrefs.editor_normal_color = *normal_color;
  3584.         set = TRUE;
  3585.     }
  3586.     if (link_color) {
  3587.         fe_globalPrefs.editor_link_color = *link_color;
  3588.         set = TRUE;
  3589.     }
  3590.     if (active_color) {
  3591.         fe_globalPrefs.editor_active_color = *active_color;
  3592.         set = TRUE;
  3593.     }
  3594.     if (followed_color) {
  3595.         fe_globalPrefs.editor_followed_color = *followed_color;
  3596.         set = TRUE;
  3597.     }
  3598.  
  3599.     fe_globalPrefs.editor_custom_colors = set;
  3600.  
  3601.     if (fe_globalPrefs.editor_background_image)
  3602.         XtFree(fe_globalPrefs.editor_background_image);
  3603.     if (background_image && background_image[0] != '\0')
  3604.         fe_globalPrefs.editor_background_image = XtNewString(background_image);
  3605.     else
  3606.         fe_globalPrefs.editor_background_image = NULL;
  3607. }
  3608.  
  3609. Boolean
  3610. fe_EditorDocumentGetImagesWithDocument(MWContext* context)
  3611. {
  3612.     Boolean keep;
  3613.     EDT_PageData* page_data = EDT_GetPageData(context);
  3614.  
  3615.     if (page_data == NULL) {
  3616.     fe_EditorPreferencesGetLinksAndImages(context, NULL, &keep);
  3617.     } else {
  3618.     keep = page_data->bKeepImagesWithDoc;
  3619.     EDT_FreePageData(page_data);
  3620.     }
  3621.  
  3622.     return keep;
  3623. }
  3624.  
  3625. void
  3626. fe_EditorDocumentSetImagesWithDocument(MWContext* context, Boolean keep)
  3627. {
  3628.     EDT_PageData* page_data = EDT_GetPageData(context);
  3629.  
  3630.     if (page_data != NULL) {
  3631.     page_data->bKeepImagesWithDoc = keep;
  3632.     EDT_SetPageData(context, page_data);
  3633.     EDT_FreePageData(page_data);
  3634.     }
  3635. }
  3636.  
  3637. char*
  3638. fe_EditorDocumentLocationGet(MWContext* context)
  3639. {
  3640.     History_entry* hist_ent;
  3641.  
  3642.     /* get the location */
  3643.     hist_ent = SHIST_GetCurrent(&context->hist);
  3644.     if (hist_ent)
  3645.     return hist_ent->address;
  3646.     else
  3647.     return NULL;
  3648. }
  3649.  
  3650. void
  3651. fe_EditorDocumentSetTitle(MWContext* context, char* name)
  3652. {
  3653.     EDT_PageData* page_data = EDT_GetPageData(context);
  3654.  
  3655.     if (!page_data)
  3656.         return;
  3657.  
  3658.     if (page_data->pTitle)
  3659.         XP_FREE(page_data->pTitle);
  3660.  
  3661.     if (name && name[0] != '\0')
  3662.         page_data->pTitle = XP_STRDUP(name);
  3663.     else
  3664.         page_data->pTitle = NULL;
  3665.  
  3666.     EDT_SetPageData(context, page_data);
  3667.  
  3668.     EDT_FreePageData(page_data);
  3669. }
  3670.  
  3671. char*
  3672. fe_EditorDocumentGetTitle(MWContext* context)
  3673. {
  3674.     EDT_PageData* page_data;
  3675.     char*         value = NULL;
  3676.  
  3677.     /* get the title */
  3678.     page_data = EDT_GetPageData(context);
  3679.     if (page_data != NULL) {
  3680.         if (page_data->pTitle != NULL && page_data->pTitle[0] != '\0')
  3681.             value = XP_STRDUP(page_data->pTitle);
  3682.     
  3683.         EDT_FreePageData(page_data);
  3684.     }
  3685.  
  3686.     return value;
  3687. }
  3688.  
  3689. #define BEGIN_DIRTY(xxx) XP_Bool dirty = FALSE
  3690.  
  3691. #define MARK_DIRTY(context)           \
  3692. if (!(dirty)) {                       \
  3693.     EDT_BeginBatchChanges((context)); \
  3694.     dirty = TRUE;                     \
  3695. }
  3696.  
  3697. #define END_DIRTY(context)            \
  3698. if ((dirty)) {                        \
  3699.     EDT_EndBatchChanges((context));   \
  3700. }
  3701.  
  3702. void
  3703. fe_EditorDocumentSetMetaData(MWContext* context, char* name, char* value)
  3704. {
  3705.     EDT_MetaData *pData = EDT_NewMetaData();
  3706.  
  3707.     BEGIN_DIRTY(context);
  3708.  
  3709.     if ( pData ) {
  3710.  
  3711.         pData->bHttpEquiv = FALSE;
  3712.         if ( name && XP_STRLEN(name) > 0 ) {
  3713.  
  3714.             MARK_DIRTY(context);
  3715.  
  3716.             pData->pName = XP_STRDUP(name);
  3717.             if ( value && XP_STRLEN(value) > 0 ) {
  3718.                 pData->pContent = XP_STRDUP(value);
  3719.                 EDT_SetMetaData(context, pData);
  3720.             } else {
  3721.                 /* (Don't really need to do this) */
  3722.                 pData->pContent = NULL; 
  3723.                 /* Remove the item */
  3724.                 EDT_DeleteMetaData(context, pData);
  3725.             }
  3726.         }
  3727.  
  3728.         EDT_FreeMetaData(pData);
  3729.     }
  3730.  
  3731.     END_DIRTY(context);
  3732. }
  3733.  
  3734. char*
  3735. fe_EditorDocumentGetMetaData(MWContext* context, char* name)
  3736. {
  3737.     EDT_MetaData* pData;
  3738.     int count;
  3739.     int i;
  3740.  
  3741.     /* lifted from winfe/edprops.cpp */
  3742.     count = EDT_MetaDataCount(context);
  3743.     for (i = 0; i < count; i++ ) {
  3744.         pData = EDT_GetMetaData(context, i);
  3745.         if (pData != NULL && !pData->bHttpEquiv) {
  3746.             if (XP_STRCASECMP(pData->pName, name) == 0) {
  3747.                 return pData->pContent;
  3748.             }
  3749.         }
  3750.     }
  3751.     return NULL;
  3752. }
  3753.  
  3754. static char* fe_editor_known_meta_data_names[] = {
  3755.     "Author",
  3756.     "Description",
  3757. #if 0 /* this one need to end up in user variables */
  3758.     "Generator",
  3759. #endif
  3760.     "Last-Modified",
  3761.     "Created",
  3762.     "Classification",
  3763.     "Keywords",
  3764.     NULL
  3765. };
  3766.  
  3767. static Boolean
  3768. fe_is_known_meta_data_name(char* name)
  3769. {
  3770.     unsigned i;
  3771.  
  3772.     for (i = 0; fe_editor_known_meta_data_names[i] != NULL; i++) {
  3773.     if (XP_STRCASECMP(fe_editor_known_meta_data_names[i], name) == 0)
  3774.         return TRUE;
  3775.     }
  3776.     return FALSE;
  3777. }
  3778.  
  3779. fe_NameValueItem*
  3780. fe_EditorDocumentGetHttpEquivMetaDataList(MWContext* context)
  3781. {
  3782.     int count = EDT_MetaDataCount(context);
  3783.     int i;
  3784.     EDT_MetaData* pData;
  3785.     fe_NameValueItem* items;
  3786.     unsigned nitems = 0;
  3787.  
  3788.     items = (fe_NameValueItem*)XtMalloc(sizeof(fe_NameValueItem)*(count+1));
  3789.  
  3790.     for (i = 0; i < count; i++) {
  3791.         pData = EDT_GetMetaData(context, i);
  3792.  
  3793.         if (pData != NULL && pData->bHttpEquiv != 0) {
  3794.             items[nitems].name = XtNewString(pData->pName);
  3795.             items[nitems].value = XtNewString(pData->pContent);
  3796.             nitems++;
  3797.         }
  3798.     }
  3799.     items[nitems].name = NULL;
  3800.     items[nitems].value = NULL;
  3801.  
  3802.     items = (fe_NameValueItem*)XtRealloc((XtPointer)items,
  3803.                      sizeof(fe_NameValueItem)*(nitems+1));
  3804.  
  3805.     return items;
  3806. }
  3807.  
  3808. void
  3809. fe_EditorDocumentSetHttpEquivMetaDataList(MWContext* context,
  3810.                       fe_NameValueItem* list)
  3811. {
  3812.     fe_NameValueItem* old_list;
  3813.     int i;
  3814.     int j;
  3815.     EDT_MetaData *meta_data;
  3816.     BEGIN_DIRTY(context);
  3817.  
  3818.     old_list = fe_EditorDocumentGetHttpEquivMetaDataList(context);
  3819.  
  3820.     /* first delete items no longer in set */
  3821.     for (i = 0; old_list[i].name != NULL; i++) {
  3822.  
  3823.         for (j = 0; list[j].name != NULL; j++) {
  3824.             if (XP_STRCASECMP(old_list[i].name, list[j].name) == 0) /* match */
  3825.                 break;
  3826.         }
  3827.  
  3828.         /* I'm sure all this thrashing of the heap can't be required ?? */
  3829.         if (list[j].name == NULL) { /* it's gone now */
  3830.             meta_data = EDT_NewMetaData();
  3831.             meta_data->pName = old_list[i].name;
  3832.             meta_data->pContent = NULL;
  3833.             MARK_DIRTY(context);
  3834.             EDT_DeleteMetaData(context, meta_data);
  3835.             EDT_FreeMetaData(meta_data);
  3836.         }
  3837.     }
  3838.  
  3839.     /* now set the ones that have changed */
  3840.     for (j = 0; list[j].name != NULL; j++) {
  3841.         meta_data = EDT_NewMetaData();
  3842.         meta_data->pName = list[j].name;
  3843.         meta_data->pContent = list[j].value;
  3844.         meta_data->bHttpEquiv = TRUE;
  3845.         MARK_DIRTY(context);
  3846.         EDT_SetMetaData(context, meta_data);
  3847.         EDT_FreeMetaData(meta_data);
  3848.     }
  3849.  
  3850.     END_DIRTY(context);
  3851. }
  3852.  
  3853. fe_NameValueItem*
  3854. fe_EditorDocumentGetAdvancedMetaDataList(MWContext* context)
  3855. {
  3856.     int count = EDT_MetaDataCount(context);
  3857.     int i;
  3858.     EDT_MetaData* pData;
  3859.     fe_NameValueItem* items;
  3860.     unsigned nitems = 0;
  3861.  
  3862.     items = (fe_NameValueItem*)XtMalloc(sizeof(fe_NameValueItem)*(count+1));
  3863.  
  3864.     for (i = 0; i < count; i++) {
  3865.         pData = EDT_GetMetaData(context, i);
  3866.  
  3867.         if (pData == NULL)
  3868.             continue;
  3869.  
  3870.         /* is it one of the ones handled in document general */
  3871.         if ((pData->bHttpEquiv) || fe_is_known_meta_data_name(pData->pName))
  3872.             continue;
  3873.     
  3874.         items[nitems].name = XtNewString(pData->pName);
  3875.         items[nitems].value = XtNewString(pData->pContent);
  3876.         nitems++;
  3877.     }
  3878.     items[nitems].name = NULL;
  3879.     items[nitems].value = NULL;
  3880.  
  3881.     items = (fe_NameValueItem*)XtRealloc((XtPointer)items,
  3882.                      sizeof(fe_NameValueItem)*(nitems+1));
  3883.  
  3884.     return items;
  3885. }
  3886.  
  3887. void
  3888. fe_EditorDocumentSetAdvancedMetaDataList(MWContext* context,
  3889.                      fe_NameValueItem* list)
  3890. {
  3891.     fe_NameValueItem* old_list;
  3892.     int i;
  3893.     int j;
  3894.     EDT_MetaData *meta_data;
  3895.     BEGIN_DIRTY(context);
  3896.  
  3897.     old_list = fe_EditorDocumentGetAdvancedMetaDataList(context);
  3898.  
  3899.     /* first delete items no longer in set */
  3900.     for (i = 0; old_list[i].name != NULL; i++) {
  3901.  
  3902.         for (j = 0; list[j].name != NULL; j++) {
  3903.             if (XP_STRCASECMP(old_list[i].name, list[j].name) == 0) /* match */
  3904.                 break;
  3905.         }
  3906.  
  3907.         /* I'm sure all this thrashing of the heap can't be required ?? */
  3908.         if (list[j].name == NULL) { /* it's gone now */
  3909.             meta_data = EDT_NewMetaData();
  3910.             meta_data->pName = old_list[i].name;
  3911.             meta_data->pContent = NULL;
  3912.             MARK_DIRTY(context);
  3913.             EDT_DeleteMetaData(context, meta_data);
  3914.             EDT_FreeMetaData(meta_data);
  3915.         }
  3916.     }
  3917.  
  3918.     /* now set the ones that have changed */
  3919.     for (j = 0; list[j].name != NULL; j++) {
  3920.         meta_data = EDT_NewMetaData();
  3921.         meta_data->pName = list[j].name;
  3922.         meta_data->pContent = list[j].value;
  3923.         MARK_DIRTY(context);
  3924.         EDT_SetMetaData(context, meta_data);
  3925.         EDT_FreeMetaData(meta_data);
  3926.     }
  3927.  
  3928.     END_DIRTY(context);
  3929. }
  3930.  
  3931. Boolean
  3932. fe_EditorDocumentGetColors(MWContext* context,
  3933.                            char*      background_image,
  3934.                            Boolean*   leave_image,
  3935.                            LO_Color*  bg_color,
  3936.                            LO_Color*  normal_color,
  3937.                            LO_Color*  link_color,
  3938.                            LO_Color*  active_color,
  3939.                            LO_Color*  followed_color)
  3940. {
  3941.     EDT_PageData* page_data = EDT_GetPageData(context);
  3942.     Boolean set = FALSE;
  3943.  
  3944.     fe_EditorDefaultGetColors(bg_color,
  3945.                               normal_color,
  3946.                               link_color, 
  3947.                               active_color,
  3948.                               followed_color);
  3949.  
  3950.     if (!page_data)
  3951.         return FALSE;
  3952.  
  3953.     if (background_image != NULL) {
  3954.         if (page_data->pBackgroundImage != NULL) {
  3955.             XP_STRCPY(background_image, page_data->pBackgroundImage);
  3956.         } else {
  3957.             background_image[0] = '\0';
  3958.         }
  3959.     }
  3960.  
  3961.     if (bg_color) {
  3962.         if (page_data->pColorBackground) {
  3963.             *bg_color = *page_data->pColorBackground;
  3964.             set = TRUE;
  3965.         }
  3966.     }
  3967.  
  3968.     if (normal_color) {
  3969.         if (page_data->pColorText) {
  3970.             *normal_color = *page_data->pColorText;
  3971.             set = TRUE;
  3972.         }
  3973.     }
  3974.  
  3975.     if (link_color) {
  3976.         if (page_data->pColorLink) {
  3977.             *link_color = *page_data->pColorLink;
  3978.             set = TRUE;
  3979.         }
  3980.     }
  3981.  
  3982.     if (active_color) {
  3983.         if (page_data->pColorActiveLink) {
  3984.             *active_color = *page_data->pColorActiveLink;
  3985.             set = TRUE;
  3986.         }
  3987.     }
  3988.  
  3989.     if (followed_color) {
  3990.         if (page_data->pColorFollowedLink) {
  3991.             *followed_color = *page_data->pColorFollowedLink;
  3992.             set = TRUE;
  3993.         }
  3994.     }
  3995.  
  3996.     if (leave_image) {
  3997.         *leave_image = page_data->bBackgroundNoSave;
  3998.     }
  3999.  
  4000.  
  4001.     EDT_FreePageData(page_data);
  4002.  
  4003.     return set;
  4004. }
  4005.  
  4006. void
  4007. fe_EditorDocumentSetColors(MWContext* context,
  4008.                            char*      background_image,
  4009.                            Boolean    leave_image,
  4010.                            LO_Color*  bg_color,
  4011.                            LO_Color*  normal_color,
  4012.                            LO_Color*  link_color,
  4013.                            LO_Color*  active_color,
  4014.                            LO_Color*  followed_color)
  4015. {
  4016.     EDT_PageData  save_data;
  4017.     EDT_PageData* page_data;
  4018.     
  4019.     if (background_image != NULL && background_image[0] == '\0')
  4020.         background_image = NULL;
  4021.     
  4022.     page_data = EDT_GetPageData(context);
  4023.  
  4024.     if (!page_data)
  4025.         return;
  4026.  
  4027.     memcpy(&save_data, page_data, sizeof(EDT_PageData));
  4028.     
  4029.     page_data->pBackgroundImage = background_image;
  4030.     page_data->pColorBackground = bg_color;
  4031.     page_data->pColorText = normal_color;
  4032.     page_data->pColorLink = link_color;
  4033.     page_data->pColorActiveLink = active_color;
  4034.     page_data->pColorFollowedLink = followed_color;
  4035.     page_data->bBackgroundNoSave = leave_image;
  4036.     
  4037.     EDT_SetPageData(context, page_data);
  4038.     memcpy(page_data, &save_data, sizeof(EDT_PageData));
  4039.     EDT_FreePageData(page_data);
  4040. }
  4041.  
  4042. typedef struct fe_EditorCommandDescription {
  4043.     intn  id;
  4044.     char* name;
  4045. } fe_EditorCommandDescription;
  4046.  
  4047. /*
  4048.  *    Yuck lifted from editor.h
  4049.  */
  4050. #define kNullCommandID 0
  4051. #define kTypingCommandID 1
  4052. #define kAddTextCommandID 2
  4053. #define kDeleteTextCommandID 3
  4054. #define kCutCommandID 4
  4055. #define kPasteTextCommandID 5
  4056. #define kPasteHTMLCommandID 6
  4057. #define kPasteHREFCommandID 7
  4058. #define kChangeAttributesCommandID 8
  4059. #define kIndentCommandID 9
  4060. #define kParagraphAlignCommandID 10
  4061. #define kMorphContainerCommandID 11
  4062. #define kInsertHorizRuleCommandID 12
  4063. #define kSetHorizRuleDataCommandID 13
  4064. #define kInsertImageCommandID 14
  4065. #define kSetImageDataCommandID 15
  4066. #define kInsertBreakCommandID 16
  4067. #define kChangePageDataCommandID 17
  4068. #define kSetMetaDataCommandID 18
  4069. #define kDeleteMetaDataCommandID 19
  4070. #define kInsertTargetCommandID 20
  4071. #define kSetTargetDataCommandID 21
  4072. #define kInsertUnknownTagCommandID 22
  4073. #define kSetUnknownTagDataCommandID 23
  4074. #define kGroupOfChangesCommandID 24
  4075. #define kSetListDataCommandID 25
  4076.  
  4077. #define kInsertTableCommandID 26
  4078. #define kDeleteTableCommandID 27
  4079. #define kSetTableDataCommandID 28
  4080.  
  4081. #define kInsertTableCaptionCommandID 29
  4082. #define kSetTableCaptionDataCommandID 30
  4083. #define kDeleteTableCaptionCommandID 31
  4084.  
  4085. #define kInsertTableRowCommandID 32
  4086. #define kSetTableRowDataCommandID 33
  4087. #define kDeleteTableRowCommandID 34
  4088.  
  4089. #define kInsertTableColumnCommandID 35
  4090. #define kSetTableCellDataCommandID 36
  4091. #define kDeleteTableColumnCommandID 37
  4092.  
  4093. #define kInsertTableCellCommandID 38
  4094. #define kDeleteTableCellCommandID 39
  4095.  
  4096. static fe_EditorCommandDescription fe_editor_commands[] = {
  4097.     { kNullCommandID,             "Null"              },
  4098.     { kTypingCommandID,           "Typing"            },
  4099.     { kAddTextCommandID,          "AddText"           },
  4100.     { kDeleteTextCommandID,       "DeleteText"        },
  4101.     { kCutCommandID,              "Cut"               },
  4102.     { kPasteTextCommandID,        "PasteText"         },
  4103.     { kPasteHTMLCommandID,        "PasteHTML"         },
  4104.     { kPasteHREFCommandID,        "PasteHREF"         },
  4105.     { kChangeAttributesCommandID, "ChangeAttributes"  },
  4106.     { kIndentCommandID,           "Indent"            },
  4107.     { kParagraphAlignCommandID,   "ParagraphAlign"    },
  4108.     { kMorphContainerCommandID,   "MorphContainer"    },
  4109.     { kInsertHorizRuleCommandID,  "InsertHorizRule"   },
  4110.     { kSetHorizRuleDataCommandID, "SetHorizRuleData"  },
  4111.     { kInsertImageCommandID,      "InsertImage"       },
  4112.     { kSetImageDataCommandID,     "SetImageData"      },
  4113.     { kInsertBreakCommandID,      "InsertBreak"       },
  4114.     { kChangePageDataCommandID,   "ChangePageData"    },
  4115.     { kSetMetaDataCommandID,      "SetMetaData"       },
  4116.     { kDeleteMetaDataCommandID,   "DeleteMetaData"    },
  4117.     { kInsertTargetCommandID,     "InsertTarget"      },
  4118.     { kSetTargetDataCommandID,    "SetTargetData"     },
  4119.     { kInsertUnknownTagCommandID, "InsertUnknownTag"  },
  4120.     { kSetUnknownTagDataCommandID,"SetUnknownTagData" },
  4121.     { kGroupOfChangesCommandID,   "GroupOfChanges"    },
  4122.     { kSetListDataCommandID,      "SetListData"       },
  4123.     { kInsertTableCommandID,      "InsertTable"       },
  4124.     { kDeleteTableCommandID,      "DeleteTable"       },
  4125.     { kSetTableDataCommandID,     "SetTableData"      },
  4126.     { kInsertTableCaptionCommandID,  "InsertTableCaption"  },
  4127.     { kSetTableCaptionDataCommandID, "SetTableCaptionData" },
  4128.     { kDeleteTableCaptionCommandID,  "DeleteTableCaption"  },
  4129.     { kInsertTableRowCommandID,    "InsertTableRow"   },
  4130.     { kSetTableRowDataCommandID,   "SetTableRowData"  },
  4131.     { kDeleteTableRowCommandID,    "DeleteTableRow"   },
  4132.     { kInsertTableColumnCommandID, "InsertTableColumn" },
  4133.     { kSetTableCellDataCommandID,  "SetTableCellData"  },
  4134.     { kDeleteTableColumnCommandID, "DeleteTableColumn" },
  4135.     { kInsertTableCellCommandID,   "InsertTableCell"  },
  4136.     { kDeleteTableCellCommandID,   "DeleteTableCell"  },
  4137.  
  4138.     { -1, NULL }
  4139. };
  4140.  
  4141. static XmString
  4142. resource_motif_string(Widget widget, char* name)
  4143. {
  4144.   XmString result = XfeSubResourceGetXmStringValue(widget,
  4145.                                                    name,
  4146.                                                    "UndoItem",
  4147.                                                    XmNlabelString,
  4148.                                                    XmCXmString,
  4149.                                                    NULL);
  4150.   
  4151.   if (!result)
  4152.       result = XmStringCreateLocalized(name);
  4153.  
  4154.   return result;
  4155. }
  4156.  
  4157. static XmString string_cache;
  4158.  
  4159. static XmString
  4160. fe_editor_undo_get_label(MWContext* context, intn id, Boolean is_undo)
  4161. {
  4162.     char     buf[64];
  4163.     XmString string;
  4164.     char* name;
  4165.     int n;
  4166.  
  4167.     name = NULL;
  4168.     for (n = 0; fe_editor_commands[n].name != NULL; n++) {
  4169.     if (fe_editor_commands[n].id == id) {
  4170.         name = fe_editor_commands[n].name;
  4171.         break;
  4172.     }
  4173.     }
  4174.  
  4175.     /*
  4176.      *    For ids we don't know yet, just show "Undo" or "Redo"
  4177.      */
  4178.     if (!name)
  4179.     name = "";
  4180.  
  4181.     /*
  4182.      *    Look for it in the cache here!!!!
  4183.      */
  4184.     /*FIXME*/
  4185.     if (string_cache)
  4186.     XmStringFree(string_cache);
  4187.  
  4188.     if (is_undo)
  4189.     XP_STRCPY(buf, "undo");
  4190.     else
  4191.     XP_STRCPY(buf, "redo");
  4192.     XP_STRCAT(buf, name);
  4193.  
  4194.     /*
  4195.      *    Resource the string.
  4196.      */
  4197.     /*
  4198.      *    Why is it so hard to get a string! Like, what,
  4199.      *    I'd never want to do that.
  4200.      */
  4201.     string = resource_motif_string(CONTEXT_DATA(context)->menubar, buf);
  4202.     string_cache = string;
  4203.  
  4204.     return string;
  4205. }
  4206.  
  4207. Boolean
  4208. fe_EditorCanUndo(MWContext* context, XmString* label_return)
  4209. {
  4210.     intn command_id = EDT_GetUndoCommandID(context, 0);
  4211.  
  4212.     if (label_return) {
  4213.     *label_return = fe_editor_undo_get_label(context,
  4214.                          command_id,
  4215.                          True);
  4216.     }
  4217.     
  4218.     if (command_id != CEDITCOMMAND_ID_NULL)
  4219.     return True;
  4220.     else
  4221.     return FALSE;
  4222. }
  4223.  
  4224. Boolean
  4225. fe_EditorCanRedo(MWContext* context, XmString* label_return)
  4226. {
  4227.     intn command_id = EDT_GetRedoCommandID(context, 0);
  4228.     
  4229.     if (label_return) {
  4230.     *label_return = fe_editor_undo_get_label(context, 
  4231.                          command_id,
  4232.                          False);
  4233.     }
  4234.     
  4235.     if (command_id != CEDITCOMMAND_ID_NULL)
  4236.     return True;
  4237.     else
  4238.     return FALSE;
  4239. }
  4240.  
  4241. void
  4242. fe_EditorUndo(MWContext* context)
  4243. {
  4244.     if (EDT_GetUndoCommandID(context, 0) != CEDITCOMMAND_ID_NULL) {
  4245.     EDT_Undo(context);
  4246.     fe_EditorUpdateToolbar(context, 0);
  4247.     } else {
  4248.     fe_Bell(context);
  4249.     }
  4250. }
  4251.  
  4252. void
  4253. fe_EditorRedo(MWContext* context)
  4254. {
  4255.     if (EDT_GetRedoCommandID(context, 0) != CEDITCOMMAND_ID_NULL) {
  4256.     EDT_Redo(context);
  4257.     fe_EditorUpdateToolbar(context, 0);
  4258.     } else {
  4259.     fe_Bell(context);
  4260.     }
  4261. }
  4262.  
  4263. Boolean
  4264. fe_EditorCanCut(MWContext* context)
  4265. {
  4266.     return (EDT_COP_OK == EDT_CanCut(context, FALSE));
  4267. }
  4268.  
  4269. Boolean
  4270. fe_EditorCanCopy(MWContext* context)
  4271. {
  4272.     return (EDT_COP_OK == EDT_CanCopy(context, TRUE));
  4273. }
  4274.  
  4275. static char fe_editor_data_name[] = "NETSCAPE_HTML";
  4276. static char fe_editor_html_name[] = "HTML";
  4277. static char fe_editor_text_name[] = "STRING";
  4278. static char fe_editor_app_name[] = "MOZILLA";
  4279.  
  4280. static Atom XFE_TEXT_ATOM = 0;
  4281. static Atom XFE_HTML_ATOM = 0;
  4282. static Atom XFE_DATA_ATOM = 0;
  4283.  
  4284. #define XFE_CCP_TEXT (fe_editor_text_name)
  4285. #define XFE_CCP_HTML (fe_editor_html_name)
  4286. #define XFE_CCP_DATA (fe_editor_data_name)
  4287. #define XFE_CCP_NAME (fe_editor_app_name)
  4288.  
  4289. #if 0
  4290. /*
  4291.  *    Cannot get this to work.
  4292.  */
  4293. static void
  4294. fe_property_notify_eh(Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
  4295. {
  4296.     MWContext* context = (MWContext *)closure;
  4297.     Display*   display = XtDisplay(CONTEXT_WIDGET(context));
  4298.     Atom       cb_atom = XmInternAtom(display, "CLIPBOARD", False);
  4299.     Atom       string_atom = XmInternAtom(display, XFE_CCP_TEXT, False);
  4300.     Atom       html_atom = XmInternAtom(display, XFE_CCP_HTML, False);
  4301.     Atom       data_atom = XmInternAtom(display, XFE_CCP_DATA, False);
  4302.     Atom       long_string_atom = XmInternAtom(display, "_MOTIF_CLIP_FORMAT_" "STRING", False);
  4303.     Atom       long_html_atom = XmInternAtom(display, "_MOTIF_CLIP_FORMAT_" "NETSCAPE_HTML", False);
  4304.     fe_EditorContextData* editor;
  4305.  
  4306. #if 0
  4307.     if (ev->xproperty.atom == XA_CUT_BUFFER0) {
  4308.     editor = EDITOR_CONTEXT_DATA(context);
  4309.     fe_editor_paste_update_cb(editor->toolbar_paste,
  4310.                   (XtPointer)context, NULL);
  4311.     }
  4312. #endif
  4313.  
  4314. #if 0
  4315.     if (ev->xproperty.atom ==  XmInternAtom (dpy, "CLIPBOARD", False)XA_CUT_BUFFER0)
  4316. #endif
  4317. }
  4318. #endif
  4319.  
  4320. Boolean
  4321. fe_EditorCanPasteData(MWContext* context, int32* r_length)
  4322. {
  4323.     Widget   mainw    = CONTEXT_WIDGET(context);
  4324.     Display* display  = XtDisplay(mainw);
  4325.     Window   window   = XtWindow(mainw);
  4326.     int      cb_result;
  4327.     unsigned long length;
  4328.  
  4329.     cb_result = XmClipboardInquireLength(display, window,
  4330.                                          XFE_CCP_DATA, &length);
  4331.  
  4332.     if (cb_result ==  ClipboardSuccess && length > 0) {
  4333.         *r_length = length;
  4334.         return TRUE;
  4335.     } else {
  4336.         *r_length = 0;
  4337.         return FALSE;
  4338.     }
  4339. }
  4340.  
  4341. Boolean
  4342. fe_EditorCanPasteHtml(MWContext* context, int32* r_length)
  4343. {
  4344.     Widget   mainw    = CONTEXT_WIDGET(context);
  4345.     Display* display  = XtDisplay(mainw);
  4346.     Window   window   = XtWindow(mainw);
  4347.     int      cb_result;
  4348.     unsigned long length;
  4349.  
  4350.     cb_result = XmClipboardInquireLength(display, window,
  4351.                                          XFE_CCP_HTML, &length);
  4352.  
  4353.     if (cb_result ==  ClipboardSuccess && length > 0) {
  4354.         *r_length = length;
  4355.         return TRUE;
  4356.     } else {
  4357.         *r_length = 0;
  4358.         return FALSE;
  4359.     }
  4360. }
  4361.  
  4362. Boolean
  4363. fe_EditorCanPasteText(MWContext* context, int32* r_length)
  4364. {
  4365.     Widget   mainw    = CONTEXT_WIDGET(context);
  4366.     Display* display  = XtDisplay(mainw);
  4367.     Window   window   = XtWindow(mainw);
  4368.     int      cb_result;
  4369.     unsigned long length;
  4370.  
  4371.     cb_result = XmClipboardInquireLength(display, window,
  4372.                                          XFE_CCP_TEXT, &length);
  4373.  
  4374.     if (cb_result ==  ClipboardSuccess && length > 0) {
  4375.         *r_length = length;
  4376.         return TRUE;
  4377.     } else {
  4378.         *r_length = 0;
  4379.         return FALSE;
  4380.     }
  4381. }
  4382.  
  4383. Boolean
  4384. fe_EditorCanPasteLocal(MWContext* context, int32* r_length)
  4385. {
  4386.     *r_length = 0;
  4387.     return FALSE;
  4388. }
  4389.  
  4390. #ifdef OSF1
  4391. extern char *fe_GetInternalHtml();
  4392. extern char *fe_GetInternalText();
  4393. #endif
  4394.  
  4395. Boolean
  4396. fe_EditorCanPasteCache(MWContext* context, int32* r_length)
  4397. {
  4398.     unsigned long text_len = 0;
  4399.     unsigned long html_len = 0;
  4400.     unsigned long data_len = 0;
  4401.     XP_Bool  sel_p = False;
  4402.  
  4403.     /*
  4404.      *    We have an "new" unified internal clipboard....
  4405.      *    Check it.
  4406.      */
  4407.     sel_p = fe_InternalSelection(True, &text_len, &html_len, &data_len);
  4408.  
  4409.     if (sel_p) {
  4410.         if (data_len > 0) {
  4411.             *r_length = data_len;
  4412.             return TRUE;
  4413.         }
  4414.         else {
  4415.             if (html_len > 0) {
  4416.                 *r_length = html_len;
  4417.                 return TRUE;
  4418.             }
  4419.             else {
  4420.                 if (text_len > 0) {
  4421.                     *r_length = text_len;
  4422.                     return TRUE;
  4423.                 }
  4424.             }
  4425.         }
  4426.     }
  4427.  
  4428.     *r_length = 0;
  4429.     return FALSE;
  4430. }
  4431.  
  4432. Boolean
  4433. fe_EditorCanPaste(MWContext* context)
  4434. {
  4435.     int32 len;
  4436.  
  4437.     /*
  4438.      *    We have to check if we can do a local paste first,
  4439.      *    because we can hang the server if we try to re-own
  4440.      *    the selection. This is all very hokey. I need to
  4441.      *    talk to jamie.
  4442.      */
  4443.     if (
  4444.     fe_EditorCanPasteLocal(context, &len)
  4445.     ||
  4446.     fe_EditorCanPasteCache(context, &len)
  4447.     ||
  4448.     fe_EditorCanPasteData(context, &len)
  4449.     || 
  4450.     fe_EditorCanPasteHtml(context, &len)
  4451.     || 
  4452.     fe_EditorCanPasteText(context, &len))
  4453.     {
  4454.     return TRUE;
  4455.     } else {
  4456.     return FALSE;
  4457.     }
  4458. }
  4459.  
  4460. void
  4461. fe_EditorCopyToClipboard(MWContext* context, char* string, Time timestamp)
  4462. {
  4463.     fe_OwnEDTSelection (context, timestamp, True, string, NULL, NULL, 0);
  4464. }
  4465.  
  4466. static void
  4467. fe_editor_report_copy_error(MWContext* context, EDT_ClipboardResult code)
  4468. {
  4469.     char* msg;
  4470.     int id;
  4471.  
  4472.     switch (code) {
  4473.     case EDT_COP_DOCUMENT_BUSY: /* IDS_DOCUMENT_BUSY */
  4474.     id = XFE_EDITOR_COPY_DOCUMENT_BUSY;
  4475.     /* Cannot copy or cut at this time, try again later. */
  4476.     break;
  4477.     case EDT_COP_SELECTION_EMPTY: /* IDS_SELECTION_EMPTY */
  4478.     id = XFE_EDITOR_COPY_SELECTION_EMPTY;
  4479.     /* Nothing is selected. */
  4480.     break;
  4481.     case EDT_COP_SELECTION_CROSSES_TABLE_DATA_CELL:
  4482.     id = XFE_EDITOR_COPY_SELECTION_CROSSES_TABLE_DATA_CELL;
  4483.     /* The selection includes a table cell boundary. */
  4484.     /* Deleting and copying are not allowed.         */
  4485.     break;
  4486.     default:
  4487.     return;
  4488.     }
  4489.  
  4490.     msg = XP_GetString(id);
  4491.     FE_Alert(context, msg);
  4492. }
  4493.  
  4494. void
  4495. fe_EditorReportCopyError(MWContext* context, EDT_ClipboardResult code)
  4496. {
  4497.     fe_editor_report_copy_error(context, code);
  4498.  
  4499. Boolean
  4500. fe_EditorOwnSelection(MWContext *context, Time time, 
  4501.                       Boolean clip_p, Boolean cut_p)
  4502. {
  4503.     char* text;
  4504.     int32 text_len;
  4505.     char* data;
  4506.     int32 data_len;
  4507.     EDT_ClipboardResult cut_result;
  4508.  
  4509.     if (cut_p && clip_p) {
  4510.         if (!fe_EditorCanCut(context)) {
  4511. #ifdef DEBUG_rhess
  4512.             fprintf(stderr, "fe_EditorOwnSelection::[ can't CUT ]\n");
  4513. #endif
  4514.             return False;
  4515.         }
  4516.  
  4517.         cut_result = EDT_CutSelection(context, 
  4518.                                       &text, &text_len,
  4519.                                       &data, &data_len);
  4520.     }
  4521.     else {
  4522.         if (!fe_EditorCanCopy(context)) {
  4523. #ifdef DEBUG_rhess
  4524.             fprintf(stderr, "fe_EditorOwnSelection::[ can't COPY ]\n");
  4525. #endif
  4526.             return False;
  4527.         }
  4528.  
  4529.         cut_result = EDT_CopySelection(context, 
  4530.                                        &text, &text_len,
  4531.                                        &data, &data_len);
  4532.     }
  4533.  
  4534.     if (cut_result != EDT_COP_OK) {
  4535.         fe_editor_report_copy_error(context, cut_result);
  4536.         return False;
  4537.     }
  4538.  
  4539.     if ((!text || text_len <= 0) && (!data || data_len <= 0))
  4540.         return False;
  4541.     
  4542.     fe_OwnEDTSelection (context, time, clip_p, text, NULL, data, data_len);
  4543.  
  4544.     return True;
  4545. }
  4546.  
  4547. void
  4548. fe_EditorDisownSelection(MWContext *context, Time time, Boolean clip_p)
  4549. {
  4550.     Widget mainw = CONTEXT_WIDGET(context);
  4551.  
  4552.     if (clip_p)
  4553.         {
  4554.             fe_DisownClipboard(mainw, time);
  4555.         }
  4556.     else
  4557.         {
  4558.             fe_DisownPrimarySelection(mainw, time);
  4559.  
  4560. #ifdef NOT_rhess
  4561.             if (!fe_ContextHasPopups(context))
  4562.                 EDT_ClearSelection(context);
  4563. #endif
  4564.         }
  4565. }
  4566.  
  4567. Boolean
  4568. fe_EditorCut(MWContext* context, Time timestamp)
  4569. {
  4570.     Boolean own_p = False;
  4571.  
  4572.     own_p = fe_EditorOwnSelection(context, timestamp, True, True);
  4573.  
  4574.     fe_EditorUpdateToolbar(context, 0);
  4575.  
  4576.     return own_p;
  4577. }
  4578.  
  4579. Boolean
  4580. fe_EditorCopy(MWContext* context, Time timestamp)
  4581. {
  4582.     Boolean own_p = False;
  4583.  
  4584.     own_p = fe_EditorOwnSelection(context, timestamp, True, False);
  4585.  
  4586.     fe_EditorUpdateToolbar(context, 0);
  4587.  
  4588.     return own_p;
  4589. }
  4590.  
  4591. static char fe_editor_local_name[] = "LOCAL";
  4592.  
  4593. #define XFE_CCP_LOCAL (fe_editor_local_name)
  4594.  
  4595. typedef struct {
  4596.     MWContext* context;
  4597.     char*  text;
  4598.     char*  html;
  4599.     char*  data;
  4600.     unsigned long text_len;
  4601.     unsigned long html_len;
  4602.     unsigned long data_len;
  4603.     int    count;
  4604.     int    max_count;
  4605. } xfe_pdata;
  4606.  
  4607. static xfe_pdata*
  4608. fe_new_pdata(MWContext* context, int max_count)
  4609. {
  4610.     xfe_pdata* pData = (xfe_pdata*) XP_ALLOC(sizeof(xfe_pdata));
  4611.  
  4612.     pData->context = context;
  4613.     pData->text = NULL;
  4614.     pData->html = NULL;
  4615.     pData->data = NULL;
  4616.     pData->text_len = 0;
  4617.     pData->html_len = 0;
  4618.     pData->data_len = 0;
  4619.     pData->count = 0;
  4620.     pData->max_count = max_count;
  4621.  
  4622.     return( pData );
  4623. }
  4624.  
  4625. static void
  4626. fe_free_pdata(xfe_pdata* pData)
  4627. {
  4628.     if (pData->text) {
  4629.         XtFree(pData->text);
  4630.     }
  4631.  
  4632.     if (pData->html) {
  4633.         XtFree(pData->html);
  4634.     }
  4635.  
  4636.     if (pData->data) {
  4637.         XtFree(pData->data);
  4638.     }
  4639.  
  4640.     pData->context = NULL;
  4641.     pData->text = NULL;
  4642.     pData->html = NULL;
  4643.     pData->data = NULL;
  4644.     pData->text_len = 0;
  4645.     pData->html_len = 0;
  4646.     pData->data_len = 0;
  4647.     pData->count = 0;
  4648.     pData->max_count = 0;
  4649.  
  4650.     XP_FREE(pData);
  4651. }
  4652.  
  4653. static void
  4654. fe_primary_sel_cb(Widget widget, XtPointer cdata, Atom *sel, Atom *type, 
  4655.                        XtPointer value, unsigned long *len, int *format)
  4656. {
  4657.     xfe_pdata* pData = (xfe_pdata*) cdata;
  4658.  
  4659.     if (value) {
  4660.         char* clip = (char *) value;
  4661.  
  4662.         if (*type == XFE_DATA_ATOM) {
  4663.             /*
  4664.              * WARNING... [ this is actually HTML data, not HTML text ]
  4665.              */
  4666. #ifdef DEBUG_rhess
  4667.             fprintf(stderr, 
  4668.                     "fe_primary_sel_cb::[ data ][ %d ]\n", *len);
  4669. #endif
  4670.             pData->count++;
  4671.             pData->data_len = *len;
  4672.             pData->data = clip;
  4673.         }
  4674.         else {
  4675.             if (*type == XFE_HTML_ATOM) {
  4676.                 /*
  4677.                  * NOTE... [ this is HTML source text ]
  4678.                  */
  4679. #ifdef DEBUG_rhess
  4680.                 fprintf(stderr, 
  4681.                         "fe_primary_sel_cb::[ html ][ %d ]\n", *len);
  4682. #endif
  4683.                 pData->count++;
  4684.                 pData->html_len = *len;
  4685.                 pData->html = clip;
  4686.             }
  4687.             else {
  4688.                 if (*type == XFE_TEXT_ATOM) {
  4689. #ifdef DEBUG_rhess
  4690.                     fprintf(stderr, 
  4691.                             "fe_primary_sel_cb::[ text ][ %d ]\n", *len);
  4692. #endif
  4693.                     pData->count++;
  4694.                     pData->text_len = *len;
  4695.                     pData->text = clip;
  4696.                 }
  4697.                 else {
  4698. #ifdef DEBUG_rhess
  4699.                     fprintf(stderr, "WARNING... [ unknown type atom ]\n");
  4700. #endif
  4701.                 }
  4702.             }
  4703.         }
  4704.     }
  4705.     else {
  4706.         pData->count++;
  4707.  
  4708. #ifdef DEBUG_rhess
  4709.         if (*type == XFE_DATA_ATOM) {
  4710.             fprintf(stderr, "fe_primary_sel_cb::[ NULL ] - DATA\n");
  4711.         }
  4712.         else {
  4713.             if (*type == XFE_HTML_ATOM) {
  4714.                 fprintf(stderr, "fe_primary_sel_cb::[ NULL ] - HTML\n");
  4715.             }
  4716.             else {
  4717.                 if (*type == XFE_TEXT_ATOM) {
  4718.                     fprintf(stderr, "fe_primary_sel_cb::[ NULL ] - TEXT\n");
  4719.                 }
  4720.                 else {
  4721.                     fprintf(stderr, "fe_primary_sel_cb::[ ERROR ]\n");
  4722.                 }
  4723.             }
  4724.         }
  4725. #endif
  4726.     }
  4727.  
  4728.     if (pData->count == pData->max_count) {
  4729.         if (pData->data_len > 0) {
  4730. #ifdef DEBUG_rhess
  4731.             fprintf(stderr, 
  4732.                     "fe_primary_sel_cb::[ PasteHTML ][ %d ]\n",
  4733.                     pData->data_len);
  4734. #endif
  4735.             EDT_PasteHTML(pData->context, pData->data);
  4736.         }
  4737.         else {
  4738.             if (pData->html_len > 0) {
  4739. #ifdef DEBUG_rhess
  4740.                 fprintf(stderr, 
  4741.                         "fe_primary_sel_cb::[ PasteQuote ][ %d ]\n",
  4742.                         pData->html_len);
  4743. #endif
  4744.                 EDT_PasteQuoteBegin(pData->context, True);
  4745.                 EDT_PasteQuote(pData->context, pData->html);
  4746.                 EDT_PasteQuoteEnd(pData->context);
  4747.             }
  4748.             else {
  4749.                 if (pData->text_len > 0) {
  4750. #ifdef DEBUG_rhess
  4751.                     fprintf(stderr, 
  4752.                             "fe_primary_sel_cb::[ PasteText ][ %d ]\n",
  4753.                             pData->text_len);
  4754. #endif
  4755.                     EDT_PasteText(pData->context, pData->text);
  4756.                 }
  4757. #ifdef DEBUG_rhess
  4758.                 else {
  4759.                     fprintf(stderr, "fe_primary_sel_cb::[ EMPTY ]\n");
  4760.                 }
  4761. #endif
  4762.             }
  4763.         }
  4764.         fe_free_pdata(pData);
  4765.     }
  4766. }
  4767.  
  4768. Boolean
  4769. fe_EditorPastePrimarySel(MWContext* context, Time timestamp)
  4770. {
  4771.     Widget         mainw = CONTEXT_WIDGET(context);
  4772.     Display*       dpy   = XtDisplay(mainw);
  4773.     char*          data  = NULL;
  4774.     unsigned long  len   = 0;
  4775.     unsigned long  text_len = 0;
  4776.     unsigned long  html_len = 0;
  4777.     unsigned long  data_len = 0;
  4778.     XP_Bool        sel_p = False;
  4779.  
  4780.     /*
  4781.      *  NOTE:  this only works if we are talking to one server... [ oops ]
  4782.      */
  4783.     if (XFE_TEXT_ATOM == 0)
  4784.         XFE_TEXT_ATOM = XmInternAtom(dpy, XFE_CCP_TEXT, False);
  4785.  
  4786.     if (XFE_HTML_ATOM == 0)
  4787.         XFE_HTML_ATOM = XmInternAtom(dpy, XFE_CCP_HTML, False);
  4788.     
  4789.     if (XFE_DATA_ATOM == 0)
  4790.         XFE_DATA_ATOM = XmInternAtom(dpy, XFE_CCP_DATA, False);
  4791.     
  4792.     /*
  4793.      *  NOTE:  first, let's see if we have an internal selection...
  4794.      *
  4795.      */
  4796.     sel_p = fe_InternalSelection(False, &text_len, &html_len, &data_len);
  4797.  
  4798.     if (sel_p) {
  4799.         if (data_len > 0) {
  4800.             data = fe_GetPrimaryData(&len);
  4801.  
  4802. #ifdef DEBUG_rhess
  4803.             fprintf(stderr, "fe_EditorPastePrimarySel::[ DATA ]\n");
  4804. #endif
  4805.             EDT_PasteHTML(context, data);
  4806.         }
  4807.         else {
  4808.             if (html_len > 0) {
  4809.                 data = fe_GetPrimaryHtml();
  4810.         
  4811. #ifdef DEBUG_rhess
  4812.                 fprintf(stderr, "fe_EditorPastePrimarySel::[ HTML ]\n");
  4813. #endif
  4814.                 EDT_PasteQuoteBegin( context, True);
  4815.                 EDT_PasteQuote( context, data);
  4816.                 EDT_PasteQuoteEnd( context );
  4817.             }
  4818.             else {
  4819.                 if (text_len > 0) {
  4820.                     data = fe_GetPrimaryText();
  4821.                 
  4822. #ifdef DEBUG_rhess
  4823.                     fprintf(stderr, "fe_EditorPastePrimarySel::[ TEXT ]\n");
  4824. #endif
  4825.                     EDT_PasteText(context, data);
  4826.                 }
  4827.             }
  4828.         }
  4829.     }
  4830.     else {
  4831.         xfe_pdata  *pData = fe_new_pdata(context, 3);
  4832.         Atom        atoms[3];
  4833.         XtPointer   tags[3];
  4834.  
  4835.         atoms[0] = XFE_TEXT_ATOM;
  4836.         atoms[1] = XFE_HTML_ATOM;
  4837.         atoms[2] = XFE_DATA_ATOM;
  4838.  
  4839.         tags[0] = (XtPointer) pData;
  4840.         tags[1] = (XtPointer) pData;
  4841.         tags[2] = (XtPointer) pData;
  4842.         
  4843.         XtGetSelectionValues(mainw, 
  4844.                              XA_PRIMARY, atoms, 3,
  4845.                              fe_primary_sel_cb, 
  4846.                              tags,
  4847.                              timestamp);
  4848.     }
  4849.     return False; /* keep compiler happy for now */
  4850. }
  4851.  
  4852. Boolean
  4853. fe_EditorPaste(MWContext* context, Time timestamp)
  4854. {
  4855.     int32   length;
  4856.     char*   tmp_data  = NULL;
  4857.     char*   clip_data = NULL;
  4858.     char*   clip_name = NULL; /* none */
  4859.     int     cb_result;
  4860.     Boolean rv = FALSE;
  4861.     Widget   mainw    = CONTEXT_WIDGET(context);
  4862.     Display* display  = XtDisplay(mainw);
  4863.     Window   window   = XtWindow(mainw);
  4864.     unsigned long len = 0;
  4865.     unsigned long text_len = 0;
  4866.     unsigned long html_len = 0;
  4867.     unsigned long data_len = 0;
  4868.     int      i;
  4869.  
  4870.  
  4871.     if (!clip_data) {
  4872.         XP_Bool sel_p = fe_InternalSelection(True, 
  4873.                                              &text_len, &html_len, &data_len);
  4874.  
  4875.         if (sel_p) {
  4876.             if (data_len > 0) {
  4877.                 tmp_data = fe_GetInternalData(&len);
  4878.  
  4879.                 clip_data = XP_ALLOC(len+1);
  4880.                 memcpy(clip_data, tmp_data, len);
  4881.                 clip_name = XFE_CCP_DATA;
  4882.             }
  4883.             else {
  4884.                 if (html_len > 0) {
  4885.                     tmp_data = fe_GetInternalHtml();
  4886.                 
  4887.                     clip_data = XP_STRDUP(tmp_data);
  4888.                     clip_name = XFE_CCP_HTML;
  4889.                 }
  4890.                 else {
  4891.                     if (text_len > 0) {
  4892.                         tmp_data = fe_GetInternalText();
  4893.                 
  4894.                         clip_data = XP_STRDUP(tmp_data);
  4895.                         clip_name = XFE_CCP_TEXT;
  4896.                     }
  4897.                 }
  4898.             }
  4899.         }
  4900.     }
  4901.  
  4902.     if (!clip_data) { /* go look on real CLIPBOARD */
  4903.  
  4904.         i = 0;
  4905.         do {
  4906.             cb_result = XmClipboardLock(display, window);
  4907. #ifdef DEBUG_rhess
  4908.             fprintf(stderr, "lockEDT::[ %d ]\n", i);
  4909. #endif
  4910.             i++;
  4911.         } while (cb_result == ClipboardLocked);
  4912.         
  4913.         if (fe_EditorCanPasteHtml(context, &length)) {
  4914.             clip_data = XP_ALLOC(length+1);
  4915.             clip_name = XFE_CCP_HTML;
  4916.         } else if (fe_EditorCanPasteText(context, &length)) {
  4917.             clip_data = XP_ALLOC(length+1);
  4918.             clip_name = XFE_CCP_TEXT;
  4919.         }
  4920.         
  4921.         cb_result = XmClipboardUnlock(display, window, TRUE);
  4922. #ifdef DEBUG_rhess
  4923.         fprintf(stderr, "fe_EditorPaste::[ unlock ]\n");
  4924. #endif
  4925.         
  4926.         if (clip_data) {
  4927.             
  4928. #ifdef DEBUG_rhess
  4929.             fprintf(stderr, "fe_EditorPaste::[ retrieve ]\n");
  4930. #endif
  4931.             cb_result = xfe_clipboard_retrieve_work(mainw,
  4932.                                                                 clip_name,
  4933.                                                                 &clip_data,
  4934.                                                                 &len,
  4935.                                                                 timestamp);
  4936. #ifdef DEBUG_rhess
  4937.             fprintf(stderr, "fe_EditorPaste::[ gotcha ]\n");
  4938. #endif
  4939.             
  4940.             if (cb_result == ClipboardSuccess) {
  4941.                 clip_data[len] = '\0';
  4942.             } else {
  4943.                 XP_FREE(clip_data);
  4944.                 clip_data = NULL;
  4945.                 clip_name = NULL;
  4946.             }
  4947.         }
  4948.     } 
  4949.  
  4950.     if (clip_name == XFE_CCP_DATA) {
  4951. #ifdef DEBUG_rhess
  4952.         fprintf (stderr, "fe_EditorPaste::[ XFE_CCP_DATA ]\n");
  4953. #endif
  4954.         rv = (EDT_PasteHTML(context, clip_data) == EDT_COP_OK);
  4955.         XP_FREE(clip_data);
  4956.     } else if (clip_name == XFE_CCP_HTML) {
  4957. #ifdef DEBUG_rhess
  4958.         fprintf (stderr, "fe_EditorPaste::[ XFE_CCP_HTML ]\n");
  4959. #endif
  4960.         EDT_PasteQuoteBegin( context, True);
  4961.         EDT_PasteQuote( context, clip_data);
  4962.         EDT_PasteQuoteEnd( context );
  4963.         XP_FREE(clip_data);
  4964.     } else if (clip_name == XFE_CCP_TEXT) {
  4965. #ifdef DEBUG_rhess
  4966.         fprintf (stderr, "fe_EditorPaste::[ XFE_CCP_TEXT ]\n");
  4967. #endif
  4968.         rv = (EDT_PasteText(context, clip_data) == EDT_COP_OK);
  4969.         XP_FREE(clip_data);
  4970.     } else if (clip_name == XFE_CCP_LOCAL) {
  4971. #ifdef DEBUG_rhess
  4972.         fprintf (stderr, "fe_EditorPaste::[ XFE_CCP_LOCAL ]\n");
  4973. #endif
  4974.         rv = (EDT_PasteText(context, clip_data) == EDT_COP_OK);
  4975.     } else {
  4976.         fe_Bell(context);
  4977.     }
  4978.  
  4979. #ifdef DONT_rhess
  4980.     fe_EditorUpdateToolbar(context, 0);
  4981. #endif
  4982.     return rv;
  4983. }
  4984.  
  4985. void
  4986. fe_EditorSelectAll(MWContext* context)
  4987. {
  4988.     Display *dpy  = XtDisplay(CONTEXT_WIDGET(context));
  4989.     Time     time = XtLastTimestampProcessed(dpy);
  4990.  
  4991.     EDT_SelectAll(context);  
  4992.  
  4993.     fe_EditorOwnSelection (context, time, False, False);
  4994.     fe_EditorUpdateToolbar(context, 0);
  4995. }
  4996.  
  4997. void
  4998. fe_EditorDeleteItem(MWContext* context, Boolean previous)
  4999. {
  5000.     EDT_ClipboardResult result;
  5001.  
  5002.     if (previous)
  5003.         result = EDT_DeletePreviousChar(context);
  5004.     else
  5005.         result = EDT_DeleteChar(context);
  5006.  
  5007.     if (result != EDT_COP_OK)
  5008.         fe_editor_report_copy_error(context, result);
  5009.  
  5010.     fe_EditorUpdateToolbar(context, 0);
  5011. }
  5012.  
  5013. Boolean
  5014. fe_EditorHorizontalRulePropertiesCanDo(MWContext* context)
  5015. {
  5016.     ED_ElementType type = EDT_GetCurrentElementType(context);
  5017.  
  5018.     if  (type == ED_ELEMENT_HRULE)
  5019.     return TRUE;
  5020.     else
  5021.     return FALSE;
  5022. }
  5023.  
  5024. void
  5025. fe_EditorHorizontalRulePropertiesSet(MWContext* context, EDT_HorizRuleData* data)
  5026. {
  5027.     if (fe_EditorHorizontalRulePropertiesCanDo(context)) {
  5028.     EDT_SetHorizRuleData(context, data);
  5029.     } else {
  5030.     EDT_InsertHorizRule(context, data);
  5031.     }
  5032. }
  5033.  
  5034. void
  5035. fe_EditorHorizontalRulePropertiesGet(MWContext* context, EDT_HorizRuleData* data)
  5036. {
  5037.     EDT_HorizRuleData* foo;
  5038.  
  5039.     if (fe_EditorHorizontalRulePropertiesCanDo(context)
  5040.         &&
  5041.         (foo = EDT_GetHorizRuleData(context)) != NULL) {
  5042.         memcpy(data, foo, sizeof(EDT_HorizRuleData));
  5043.         EDT_FreeHorizRuleData(foo);
  5044.     } else {
  5045.         data->size = 2;
  5046.         data->iWidth = 100;
  5047.         data->bWidthPercent = TRUE;
  5048.         data->align = ED_ALIGN_CENTER;
  5049.         data->bNoShade = FALSE;
  5050.     }
  5051. }
  5052.  
  5053. void
  5054. fe_EditorRefresh(MWContext* context)
  5055. {
  5056.     EDT_RefreshLayout(context);    
  5057. }
  5058.  
  5059. void
  5060. fe_EditorHrefInsert(MWContext* context, char* p_text, char* p_url)
  5061. {
  5062.     char* text;
  5063.     char* url;
  5064.     EDT_ClipboardResult result;
  5065.  
  5066.     if (!EDT_CanSetHREF(context)) { /* should not exist already */
  5067.  
  5068.         if (p_url && p_url[0] != '\0')
  5069.             url = XP_STRDUP(p_url);
  5070.         else
  5071.             return; /* no url specified */
  5072.  
  5073.         if (p_text && p_text[0] != '\0')
  5074.             text = XP_STRDUP(p_text);
  5075.         else
  5076.             text = XP_STRDUP(p_url);
  5077.  
  5078.         result = EDT_PasteHREF(context, &url, &text, 1);
  5079.     
  5080.         if (result != EDT_COP_OK)
  5081.             fe_editor_report_copy_error(context, result);
  5082.     }
  5083. }
  5084.  
  5085. Boolean
  5086. fe_EditorGetHref(MWContext *context) {
  5087.     char*         p;
  5088.  
  5089.     p = (char *) LO_GetSelectionText(context);
  5090.     if (p == NULL) return False;
  5091.     else
  5092.     return NULL != EDT_GetHREF(context);
  5093. }
  5094.  
  5095.  
  5096. Boolean
  5097. fe_EditorHrefGet(MWContext* context, char** text, char** url)
  5098. {
  5099.     EDT_HREFData* href_data = EDT_GetHREFData(context);
  5100.     Bool          is_selected = EDT_IsSelected(context);
  5101.     char*         p;
  5102.  
  5103.     p = (char *) LO_GetSelectionText(context);
  5104.  
  5105.     if (is_selected && p != NULL) {
  5106.     *text = XtNewString(p);
  5107.     XP_FREE(p);
  5108.     } else if (p == NULL) {   /* this fixes #27762 */
  5109.     *text = NULL;
  5110.     } else if ((p = EDT_GetHREFText(context)) != NULL) { 
  5111.             /* charlie's new get the text of a link thing */
  5112.     *text = p;
  5113.     } else {
  5114.     *text = NULL;
  5115.     }
  5116.     
  5117.     if (href_data != NULL && (p = href_data->pURL) != NULL) {
  5118.     *url = XtNewString(p);
  5119.     } else {
  5120.     *url = NULL;
  5121.     }
  5122.  
  5123.     if (href_data != NULL)
  5124.     EDT_FreeHREFData(href_data);
  5125.  
  5126.     return EDT_CanSetHREF(context);
  5127. }
  5128.  
  5129. void
  5130. fe_EditorHrefSetUrl(MWContext* context, char* url)
  5131. {
  5132.     EDT_HREFData* href_data;
  5133.  
  5134.     if (EDT_CanSetHREF(context)) {
  5135.  
  5136.     href_data = EDT_GetHREFData(context);
  5137.  
  5138.     if (!href_data)
  5139.         href_data = EDT_NewHREFData();
  5140.  
  5141.     if (href_data->pURL)
  5142.         XP_FREE(href_data->pURL);
  5143.     
  5144.     if (url)
  5145.         href_data->pURL = XP_STRDUP(url);
  5146.     else
  5147.         href_data->pURL = NULL; /* clear the href */
  5148.  
  5149.     EDT_SetHREFData(context, href_data);
  5150.  
  5151.     EDT_FreeHREFData(href_data);
  5152.     }
  5153. }
  5154.  
  5155. void
  5156. fe_EditorHrefClearUrl(MWContext* context)
  5157. {
  5158.     fe_EditorHrefSetUrl(context, NULL);
  5159. }
  5160.  
  5161. void
  5162. fe_EditorRemoveLinks(MWContext* context)
  5163. {
  5164.     /*
  5165.      *    Remove a single link or all links within selected region.
  5166.      */
  5167.     if (EDT_CanSetHREF(context)) {
  5168.         EDT_SetHREF(context, NULL);
  5169.     }
  5170. }
  5171.  
  5172. static Time
  5173. fe_getTimeFromEvent(MWContext* context, XEvent* event)
  5174. {
  5175.   Time time;
  5176.   time = (event && (event->type == KeyPress ||
  5177.             event->type == KeyRelease)
  5178.            ? event->xkey.time :
  5179.            event && (event->type == ButtonPress ||
  5180.              event->type == ButtonRelease)
  5181.            ? event->xbutton.time :
  5182.            XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  5183.   return time;
  5184. }
  5185.  
  5186. Boolean
  5187. fe_EditorPropertiesDialogCanDo(MWContext* context,
  5188.                    fe_EditorPropertiesDialogType d_type)
  5189. {
  5190.     ED_ElementType e_type;
  5191.  
  5192.     if (
  5193.     d_type == XFE_EDITOR_PROPERTIES_IMAGE_INSERT
  5194.     ||
  5195.     d_type == XFE_EDITOR_PROPERTIES_LINK_INSERT
  5196.     ||
  5197.     d_type == XFE_EDITOR_PROPERTIES_CHARACTER
  5198.     ||
  5199.     d_type == XFE_EDITOR_PROPERTIES_PARAGRAPH
  5200.     ||
  5201.     d_type == XFE_EDITOR_PROPERTIES_TABLE
  5202.     || 
  5203.     d_type == XFE_EDITOR_PROPERTIES_DOCUMENT
  5204.     )
  5205.     return TRUE; /* always ok to do */
  5206.  
  5207.     e_type = EDT_GetCurrentElementType(context);
  5208.  
  5209.     if (d_type == XFE_EDITOR_PROPERTIES_IMAGE) {
  5210.     if (e_type == ED_ELEMENT_IMAGE)
  5211.         return TRUE;
  5212.     else
  5213.         return FALSE;
  5214.  
  5215.     } else if (d_type == XFE_EDITOR_PROPERTIES_HRULE) {
  5216.     if (e_type == ED_ELEMENT_HRULE)
  5217.         return TRUE;
  5218.     else
  5219.         return FALSE;
  5220.  
  5221.     } else if (d_type == XFE_EDITOR_PROPERTIES_HTML_TAG) {
  5222.     if (e_type == ED_ELEMENT_UNKNOWN_TAG)
  5223.         return TRUE;
  5224.     else
  5225.         return FALSE;
  5226.  
  5227.     } else if (d_type == XFE_EDITOR_PROPERTIES_TARGET) {
  5228.     if (e_type == ED_ELEMENT_TARGET)
  5229.         return TRUE;
  5230.     else
  5231.         return FALSE;
  5232.  
  5233.     } else if (d_type == XFE_EDITOR_PROPERTIES_LINK) {
  5234.     if (EDT_GetHREF(context))
  5235.         return TRUE;
  5236.     else
  5237.         return FALSE;
  5238.     } 
  5239.     return FALSE;
  5240. }
  5241.  
  5242. /*
  5243.  *    This stuff is so crazy.
  5244.  *
  5245.  */
  5246. void
  5247. fe_EditorParagraphPropertiesSetAll(MWContext*    context,
  5248.                    TagType       paragragh_type,
  5249.                    EDT_ListData* list_data,
  5250.                    ED_Alignment  align)
  5251. {
  5252.     TagType       old_paragraph_type = EDT_GetParagraphFormatting(context);
  5253.     EDT_ListData* old_list_data = EDT_GetListData(context);
  5254.     Boolean       do_set;
  5255.  
  5256.     EDT_BeginBatchChanges(context);
  5257.  
  5258.     /*
  5259.      *    Windows has this kludge, so...
  5260.      */
  5261.     if (align == ED_ALIGN_LEFT)
  5262.     align = ED_ALIGN_DEFAULT;
  5263.  
  5264.     EDT_SetParagraphAlign(context, align);
  5265.  
  5266.     /*
  5267.      *    If there was a list before, and now there is none,
  5268.      *    remove the list.
  5269.      */
  5270.     if (old_list_data && !list_data) {
  5271.     for ( ; old_list_data; old_list_data = EDT_GetListData(context)) {
  5272.         EDT_FreeListData(old_list_data);
  5273.         EDT_Outdent(context);
  5274.     }
  5275.     old_list_data = NULL;
  5276.     }
  5277.     
  5278.     /*
  5279.      *    If the style has changed.
  5280.      */
  5281.     if (paragragh_type != old_paragraph_type)
  5282.     EDT_MorphContainer(context, paragragh_type);
  5283.  
  5284.     /*
  5285.      *    If there was no list, and now there is..
  5286.      */
  5287.     if (!old_list_data && list_data) {
  5288.     EDT_Indent(context);
  5289.     old_list_data = EDT_GetListData(context);
  5290.     }
  5291.  
  5292.     /*
  5293.      *    The BE is losing. It cannot deal with lists in selections,
  5294.      *    it returns no list data. So, we protect oursleves and
  5295.      *    end up doing nothing, just like windows.
  5296.      */
  5297.     if (old_list_data != NULL) {
  5298.  
  5299.     do_set = TRUE;
  5300.  
  5301.     /*
  5302.      *    If this is a block quote..
  5303.      */
  5304.     if (list_data != NULL && list_data->iTagType == P_BLOCKQUOTE) {
  5305.         old_list_data->iTagType = P_BLOCKQUOTE;
  5306.         old_list_data->eType = ED_LIST_TYPE_DEFAULT;
  5307.     }
  5308.  
  5309.     /*
  5310.      *    If it's a list.
  5311.      */
  5312.     else if (list_data != NULL) {
  5313.         old_list_data->iTagType = list_data->iTagType;
  5314.         old_list_data->eType = ED_LIST_TYPE_DEFAULT;
  5315. #if 0
  5316.         /*
  5317.          *    We have no UI for this, but maybe it's in  the author's
  5318.          *    HTML. Don't change it. Actually, I have no idea.
  5319.          */
  5320.         old_list_data->bCompact = FALSE;
  5321. #endif
  5322.         switch (list_data->iTagType) {
  5323.         case P_UNUM_LIST:
  5324.         if (list_data->eType == ED_LIST_TYPE_DISC   ||
  5325.             list_data->eType == ED_LIST_TYPE_SQUARE    ||
  5326.             list_data->eType == ED_LIST_TYPE_CIRCLE)
  5327.             old_list_data->eType = list_data->eType;
  5328.         break;
  5329.         case P_NUM_LIST:
  5330.         if (list_data->eType == ED_LIST_TYPE_DIGIT       ||
  5331.             list_data->eType == ED_LIST_TYPE_BIG_ROMAN   ||
  5332.             list_data->eType == ED_LIST_TYPE_SMALL_ROMAN ||
  5333.             list_data->eType == ED_LIST_TYPE_BIG_LETTERS ||
  5334.             list_data->eType == ED_LIST_TYPE_SMALL_LETTERS)
  5335.             old_list_data->eType = list_data->eType;
  5336.         if (list_data->iStart > 0)
  5337.             old_list_data->iStart = list_data->iStart;
  5338.         else
  5339.             old_list_data->iStart = 1;
  5340.         break;
  5341.         case P_DIRECTORY:
  5342.         case P_MENU:
  5343.         case P_DESC_LIST:
  5344.         break;
  5345.         default: /* garbage, don't set */
  5346.         do_set = FALSE;
  5347.         break;
  5348.         }
  5349.     }
  5350.  
  5351.     if (do_set)
  5352.         EDT_SetListData(context, old_list_data);
  5353.     }
  5354.  
  5355.     /*
  5356.      *    Else it's just an ordinary old jo.
  5357.      */
  5358.     /* nothing to do */
  5359.  
  5360.     if (old_list_data != NULL)
  5361.     EDT_FreeListData(old_list_data);
  5362.  
  5363.     EDT_EndBatchChanges(context);
  5364.     
  5365.     fe_EditorUpdateToolbar(context, 0);
  5366. }
  5367.  
  5368. Boolean
  5369. fe_EditorParagraphPropertiesGetAll(MWContext*    context,
  5370.                    TagType*      paragragh_type,
  5371.                    EDT_ListData* list_data,
  5372.                    ED_Alignment* align)
  5373. {
  5374.     TagType       old_paragraph_type = EDT_GetParagraphFormatting(context);
  5375.     EDT_ListData* old_list_data = EDT_GetListData(context);
  5376.  
  5377.     if (paragragh_type)
  5378.     *paragragh_type = old_paragraph_type;
  5379.  
  5380.     if (list_data && old_list_data)
  5381.     *list_data = *old_list_data;
  5382.  
  5383.     if (align)
  5384.     *align = EDT_GetParagraphAlign(context);
  5385.  
  5386.     if (old_list_data != NULL)
  5387.     EDT_FreeListData(old_list_data);
  5388.  
  5389.     return (old_list_data != NULL);
  5390. }
  5391.  
  5392. /*FIXME*/
  5393. /*
  5394.  *    I think the following routine could now be replaced
  5395.  *    by EDT_SetFontColor(context, &color);
  5396.  */
  5397. void
  5398. fe_EditorColorSet(MWContext* context, LO_Color* color)
  5399. {
  5400.     EDT_CharacterData cdata;
  5401.  
  5402.     memset(&cdata, 0, sizeof(EDT_CharacterData));
  5403.  
  5404.     cdata.mask = TF_FONT_COLOR;
  5405.     cdata.pColor = color;
  5406.  
  5407.     if (color)
  5408.     cdata.values = TF_FONT_COLOR;
  5409.     else
  5410.     cdata.values = 0;
  5411.  
  5412.     EDT_SetCharacterData(context, &cdata);
  5413. }
  5414.  
  5415. Boolean
  5416. fe_EditorColorGet(MWContext* context, LO_Color* color)
  5417. {
  5418.     EDT_CharacterData* cdata = EDT_GetCharacterData(context);
  5419.     Boolean   rv = FALSE;
  5420.     LO_Color* use_color = NULL;
  5421.  
  5422.     if (cdata != NULL && (cdata->values & TF_FONT_COLOR) != 0) { /* custom */
  5423.         rv = TRUE; /* custom */
  5424.         if ((cdata->mask & TF_FONT_COLOR) != 0 && cdata->pColor != NULL) {
  5425.             use_color = cdata->pColor; /* defined */
  5426.         }
  5427.     }
  5428.  
  5429.     if (use_color != NULL) {
  5430.         *color = *use_color;
  5431.     } else {
  5432.         fe_EditorDocumentGetColors(context,
  5433.                                    NULL, /* bg image */
  5434.                                    NULL, /* leave image */
  5435.                                    NULL, /* bg color */
  5436.                                    color,/* normal color */
  5437.                                    NULL, /* link color */
  5438.                                    NULL, /* active color */
  5439.                                    NULL); /* followed color */
  5440.     }
  5441.  
  5442.     if (cdata != NULL)
  5443.         EDT_FreeCharacterData(cdata);
  5444.  
  5445.     return rv; /* custom */
  5446. }
  5447.  
  5448. extern int XFE_COULDNT_FORK;
  5449. extern int XFE_EXECVP_FAILED;
  5450.  
  5451. void
  5452. fe_ExecCommand(MWContext* context, char** argv)
  5453. {
  5454.     char buf[MAXPATHLEN];
  5455.     int forked;
  5456.  
  5457.     switch (forked = fork()) {
  5458.     case -1:
  5459.     fe_perror(context, XP_GetString(XFE_COULDNT_FORK));
  5460.     break;
  5461.     case 0: {
  5462.     Display *dpy = XtDisplay(CONTEXT_WIDGET(context));
  5463.     close(ConnectionNumber(dpy));
  5464.  
  5465.     execvp(argv[0], argv);
  5466.  
  5467.     PR_snprintf(buf, sizeof(buf), XP_GetString(XFE_EXECVP_FAILED),
  5468.             fe_progname, argv[0]);
  5469.     perror(buf);
  5470.     exit(3);    /* Note that this only exits a child fork.  */
  5471.     break;
  5472.     }
  5473.     default:
  5474.     /* block */
  5475.     break;
  5476.     }
  5477. }
  5478.  
  5479. static char**
  5480. fe_editor_parse_argv(char* string, char* filename)
  5481. {
  5482.     char     buf[MAXPATHLEN];
  5483.     unsigned size = 32;
  5484.     unsigned argc = 0;
  5485.     char**   argv = (char**)malloc(sizeof(char*) * size);
  5486.     char*    p;
  5487.     char*    q;
  5488.     char*    r;
  5489.  
  5490.     for (p = string; *p != '\0'; ) {
  5491.  
  5492.     q = buf;
  5493.  
  5494.     /* skip leading white */
  5495.     while (isspace(*p))
  5496.         p++;
  5497.  
  5498.     while (!isspace(*p) && *p != '\0' && ((q - buf) < sizeof(buf))) {
  5499.         if (*p == '%' && p[1] == 'f') {
  5500.         for (r = filename; *r != '\0'; ) {
  5501.             *q++ = *r++;
  5502.         }
  5503.         p += 2;
  5504.         } else {
  5505.         *q++ = *p++;
  5506.         }
  5507.     }
  5508.     *q = '\0';
  5509.  
  5510.     if (q > buf)
  5511.         argv[argc++] = strdup(buf);
  5512.  
  5513.     if (argc == size) {
  5514.         size = argc + 32;
  5515.         argv = (char**)realloc((void*)argv, sizeof(char*) * size);
  5516.     }
  5517.     }
  5518.  
  5519.     if (argc > 0) {
  5520.     argv[argc] = NULL;
  5521.     return argv;
  5522.     } else {
  5523.     free(argv);
  5524.     return NULL;
  5525.     }
  5526. }
  5527.  
  5528. void
  5529. fe_editor_free_argv(char** argv)
  5530. {
  5531.     unsigned i;
  5532.     for (i = 0; argv[i]; i++)
  5533.     free(argv[i]);
  5534.     free(argv);
  5535. }
  5536.  
  5537. void
  5538. fe_editor_exec_command(MWContext* context, char* command, char* filename)
  5539. {
  5540.     char** argv;
  5541.  
  5542.     if ((argv = fe_editor_parse_argv(command, filename)) != NULL) {
  5543.  
  5544.     fe_ExecCommand(context, argv);
  5545.  
  5546.     fe_editor_free_argv(argv);
  5547.     } else {
  5548.     /* Empty command specified! */
  5549.     FE_Alert(context, XP_GetString(XFE_COMMAND_EMPTY));
  5550.     }
  5551. }
  5552.  
  5553. void
  5554. fe_EditorEditSource(MWContext* context)
  5555. {
  5556.     char* html_editor;
  5557.     char* local_name;
  5558.     History_entry* hist_entry;
  5559.  
  5560.     if (!FE_CheckAndSaveDocument(context))
  5561.         return;
  5562.     fe_EditorPreferencesGetEditors(context, &html_editor, NULL);
  5563.  
  5564.     if (html_editor == NULL || XP_STRSTR(html_editor, "%f") == NULL) {
  5565.         /*
  5566.          * "Please specify an editor in Editor Preferences.\n"
  5567.          * "Specify the file argument with %f. Netscape will\n"
  5568.          * "replace %f with the correct file name. Examples:\n"
  5569.          * "             xterm -e vi %f\n"
  5570.          * "             xgifedit %f\n"
  5571.          */
  5572.         char* msg = XP_GetString(XFE_EDITOR_HTML_EDITOR_COMMAND_EMPTY);
  5573.     
  5574.           if (XFE_Confirm(context, msg)) {
  5575.             fe_EditorShowNewPreferences(context); /* call C++ adaptor */
  5576.         }
  5577.  
  5578.         return;
  5579.     } 
  5580.  
  5581.     hist_entry = SHIST_GetCurrent(&context->hist);
  5582.     if (hist_entry && hist_entry->address) {
  5583.         if (XP_ConvertUrlToLocalFile(hist_entry->address, &local_name)) {
  5584.             fe_editor_exec_command(context, html_editor, local_name);
  5585.             XP_FREE(local_name);
  5586.         }
  5587.     }
  5588. }
  5589.  
  5590. void
  5591. fe_EditorEditImage(MWContext* context, char* file)
  5592. {
  5593.     char* image_editor;
  5594.     char* local_name = NULL;
  5595.     char* full_file;
  5596.     char* directory;
  5597.     char* p;
  5598.     History_entry* hist_entry;
  5599.  
  5600.     fe_EditorPreferencesGetEditors(context, NULL, &image_editor);
  5601.  
  5602.     if (image_editor == NULL || XP_STRSTR(image_editor, "%f") == NULL) {
  5603.         /*
  5604.          * "Please specify an editor in Editor Preferences.\n"
  5605.          * "Specify the file argument with %f. Netscape will\n"
  5606.          * "replace %f with the correct file name. Examples:\n"
  5607.          * "             xterm -e vi %f\n"
  5608.          * "             xgifedit %f\n"
  5609.          */
  5610.         char* msg = XP_GetString(XFE_EDITOR_IMAGE_EDITOR_COMMAND_EMPTY);
  5611.  
  5612.           if (XFE_Confirm(context, msg)) {
  5613.             fe_EditorShowNewPreferences(context); /* call C++ adaptor */
  5614.         }
  5615.  
  5616.         return;
  5617.     }
  5618.  
  5619.     while (isspace(*file))
  5620.         file++;
  5621.  
  5622.     if (file[0] != '/') { /* not absolute */
  5623.         hist_entry = SHIST_GetCurrent(&context->hist);
  5624.         if (hist_entry && hist_entry->address) {
  5625.             if (XP_ConvertUrlToLocalFile(hist_entry->address, &local_name)) {
  5626.                 p = strrchr(local_name, '/'); /* find last slash */
  5627.                 if (p) {
  5628.                     *p = '\0';
  5629.                     directory = local_name;
  5630.                 } else {
  5631.                     directory = ".";
  5632.                 }
  5633.                 full_file = (char*)XtMalloc(strlen(directory) +
  5634.                                             strlen(file) + 2);
  5635.                 sprintf(full_file, "%s/%s", directory, file);
  5636.                 XP_FREE(local_name);
  5637.  
  5638.                 fe_editor_exec_command(context, image_editor, full_file);
  5639.                 XtFree(full_file);
  5640.             }
  5641.         }
  5642.     } else {
  5643.         fe_editor_exec_command(context, image_editor, file);
  5644.     }
  5645. }
  5646.  
  5647. #define COPY_SAVE_EXTRA(b, a) \
  5648. { char* xx_extra = (b)->pExtra; *(b) = *(a); (b)->pExtra = xx_extra; }
  5649.  
  5650. #define COPY_SAVE_BGCOLOR(b, a) \
  5651. { char* xx_bgcolor = (b)->pColorBackground; *(b) = *(a); (b)->pColorBackground = xx_bgcolor; }
  5652.  
  5653. static LO_Color*
  5654. fe_dup_lo_color(LO_Color* color)
  5655. {
  5656.     LO_Color* new_color;
  5657.  
  5658.     if (color != NULL && (new_color = (LO_Color*)XtNew(LO_Color)) != NULL) {
  5659.     *new_color = *color;
  5660.     return new_color;
  5661.     } else {
  5662.     return NULL;
  5663.     }
  5664. }
  5665.  
  5666. #define DUP_BGCOLOR(b, a) \
  5667. { (b)->pColorBackground = fe_dup_lo_color((a)->pColorBackground); }
  5668.  
  5669. /*
  5670.  *    Table support.
  5671.  */
  5672. Boolean
  5673. fe_EditorTableCanInsert(MWContext* context)
  5674. {
  5675.     return !EDT_IsJavaScript(context);
  5676. }
  5677.  
  5678. void
  5679. fe_EditorTableInsert(MWContext* context, EDT_AllTableData* all_data)
  5680. {
  5681.     EDT_TableData* new_data = EDT_NewTableData();
  5682.     EDT_TableCaptionData* caption_data;
  5683.     
  5684.     if (all_data) {
  5685.         EDT_TableData* data = &all_data->td;
  5686.         COPY_SAVE_EXTRA(new_data, data);
  5687.         DUP_BGCOLOR(new_data, data);
  5688.     } else {
  5689.         new_data->iBorderWidth = 1;
  5690.         new_data->iRows = 2;
  5691.         new_data->iColumns = 2;
  5692.     }
  5693.     EDT_BeginBatchChanges(context);
  5694.  
  5695.     EDT_InsertTable(context, new_data);
  5696.  
  5697.     if (all_data != NULL && all_data->has_caption) {
  5698.         caption_data = EDT_NewTableCaptionData();
  5699.         caption_data->align = all_data->cd.align;
  5700.         EDT_InsertTableCaption(context, caption_data);
  5701.     }
  5702.  
  5703.     EDT_FreeTableData(new_data);
  5704.  
  5705.     EDT_EndBatchChanges(context);
  5706. }
  5707.  
  5708. Boolean
  5709. fe_EditorTableCanDelete(MWContext* context)
  5710. {
  5711.     return (EDT_IsInsertPointInTable(context) != 0);
  5712. }
  5713.  
  5714. void
  5715. fe_EditorTableDelete(MWContext* context)
  5716. {
  5717.     if (EDT_IsInsertPointInTable(context) != 0) {
  5718.     EDT_DeleteTable(context);
  5719.     fe_EditorUpdateToolbar(context, 0);
  5720.     }
  5721. }
  5722.  
  5723. Boolean
  5724. fe_EditorTableGetData(MWContext* context, EDT_AllTableData* all_data)
  5725. {
  5726.     Boolean in_table = FALSE;
  5727.     EDT_TableData* table_data = EDT_GetTableData(context);
  5728.     EDT_TableData* pt_data = &all_data->td;
  5729.     EDT_TableCaptionData* caption_data;
  5730.  
  5731.     if (table_data) {
  5732.         *pt_data = *table_data;
  5733.         if (table_data->pColorBackground != NULL) {
  5734.             static LO_Color color_buf;
  5735.             color_buf = *table_data->pColorBackground;
  5736.             pt_data->pColorBackground = &color_buf; /*caller cannot hang on*/
  5737.         }
  5738.     
  5739.         if (table_data->pBackgroundImage != NULL) {
  5740.             static char* bg_image;
  5741.             if (bg_image != NULL)
  5742.                 XP_FREE(bg_image);
  5743.             bg_image = XP_STRDUP(table_data->pBackgroundImage);
  5744.             pt_data->pBackgroundImage = bg_image; /*caller cannot hang on*/
  5745.         }
  5746.     
  5747.         EDT_FreeTableData(table_data);
  5748.         in_table = TRUE;
  5749.     } else {
  5750.         return FALSE;
  5751.     }
  5752.  
  5753.     if (EDT_IsInsertPointInTableCaption(context)
  5754.         &&
  5755.         (caption_data = EDT_GetTableCaptionData(context)) != NULL) {
  5756.         
  5757.         all_data->has_caption = TRUE;
  5758.         all_data->cd.align = caption_data->align;
  5759.     } else {
  5760.         all_data->has_caption = FALSE;
  5761.         all_data->cd.align = ED_ALIGN_TOP;
  5762.     }
  5763.     return TRUE;
  5764. }
  5765.  
  5766. void
  5767. fe_EditorTableSetData(MWContext* context, EDT_AllTableData* all_data)
  5768. {
  5769.     Boolean has_caption;
  5770.     Boolean wants_caption;
  5771.     EDT_TableData* table_data = EDT_GetTableData(context);
  5772.     EDT_TableCaptionData* caption_data;
  5773.  
  5774.     if (table_data) {
  5775.         EDT_BeginBatchChanges(context);
  5776.  
  5777.         /* get the basic table data */
  5778.         COPY_SAVE_EXTRA(table_data, &all_data->td);
  5779.         DUP_BGCOLOR(table_data, &all_data->td);
  5780.  
  5781.         EDT_SetTableData(context, table_data);
  5782.  
  5783.         caption_data = NULL;
  5784.         has_caption = EDT_IsInsertPointInTableCaption(context);
  5785.         wants_caption = all_data->has_caption;
  5786.  
  5787.         if (has_caption == TRUE && wants_caption == FALSE) {
  5788.             EDT_DeleteTableCaption(context);
  5789.         } else if (has_caption == FALSE && wants_caption == TRUE) {
  5790.             caption_data = EDT_NewTableCaptionData();
  5791.             caption_data->align = all_data->cd.align;
  5792.             EDT_InsertTableCaption(context, caption_data);
  5793.         } else if (has_caption
  5794.                    &&
  5795.                    (caption_data = EDT_GetTableCaptionData(context)) != NULL) {
  5796.             if (caption_data->align != all_data->cd.align) {
  5797.                 caption_data->align = all_data->cd.align;
  5798.                 EDT_SetTableCaptionData(context, caption_data);
  5799.             }
  5800.         }
  5801.  
  5802.         EDT_BeginBatchChanges(context);
  5803.  
  5804.         if (caption_data)
  5805.             EDT_FreeTableCaptionData(caption_data);
  5806.  
  5807.         EDT_FreeTableData(table_data);
  5808.     }
  5809. }
  5810.  
  5811. Boolean
  5812. fe_EditorTableRowCanInsert(MWContext* context)
  5813. {
  5814.     return (EDT_IsInsertPointInTableRow(context) != 0);
  5815. }
  5816.  
  5817. void
  5818. fe_EditorTableRowInsert(MWContext* context, EDT_TableRowData* data)
  5819. {
  5820.     EDT_TableRowData* new_data;
  5821.  
  5822.     if (!fe_EditorTableRowCanInsert(context)) {
  5823.         fe_Bell(context);
  5824.         return;
  5825.     }
  5826.  
  5827.     new_data = EDT_GetTableRowData(context);
  5828.  
  5829.     if (!new_data)
  5830.         return;
  5831.  
  5832.     if (data) {
  5833.         new_data->align = data->align;
  5834.         new_data->valign = data->valign;
  5835.         DUP_BGCOLOR(new_data, data);
  5836.     } 
  5837.     EDT_InsertTableRows(context, new_data, TRUE, 1);
  5838.     EDT_FreeTableRowData(new_data);
  5839.     fe_EditorUpdateToolbar(context, 0);
  5840. }
  5841.  
  5842. Boolean
  5843. fe_EditorTableRowCanDelete(MWContext* context)
  5844. {
  5845.     return (EDT_IsInsertPointInTableRow(context) != 0);
  5846. }
  5847.  
  5848. void
  5849. fe_EditorTableRowDelete(MWContext* context)
  5850. {
  5851.     if (EDT_IsInsertPointInTable(context) != 0) {
  5852.     EDT_DeleteTableRows(context, 1);
  5853.     fe_EditorUpdateToolbar(context, 0);
  5854.     }
  5855. }
  5856.  
  5857. Boolean
  5858. fe_EditorTableRowGetData(MWContext* context, EDT_TableRowData* p_data)
  5859. {
  5860.     EDT_TableRowData* row_data = EDT_GetTableRowData(context);
  5861.  
  5862.     if (row_data) {
  5863.         *p_data = *row_data;
  5864.         if (row_data->pColorBackground != NULL) {
  5865.             static LO_Color color_buf;
  5866.             color_buf = *row_data->pColorBackground;
  5867.             p_data->pColorBackground = &color_buf; /*caller cannot hang on*/
  5868.         }
  5869.         EDT_FreeTableRowData(row_data);
  5870.         return TRUE;
  5871.     } else {
  5872.         return FALSE;
  5873.     }
  5874. }
  5875.  
  5876. void
  5877. fe_EditorTableRowSetData(MWContext* context, EDT_TableRowData* p_data)
  5878. {
  5879.     EDT_TableRowData* row_data = EDT_GetTableRowData(context);
  5880.  
  5881.     if (row_data) {
  5882.     COPY_SAVE_EXTRA(row_data, p_data);
  5883.     DUP_BGCOLOR(row_data, p_data);
  5884.     EDT_SetTableRowData(context, row_data);    
  5885.     EDT_FreeTableRowData(row_data);
  5886.     fe_EditorUpdateToolbar(context, 0);
  5887.     }
  5888. }
  5889.  
  5890. Boolean
  5891. fe_EditorTableCaptionCanInsert(MWContext* context)
  5892. {
  5893.     return (EDT_IsInsertPointInTable(context) != 0);
  5894. }
  5895.  
  5896. void
  5897. fe_EditorTableCaptionInsert(MWContext* context, EDT_TableCaptionData* data)
  5898. {
  5899.     EDT_TableCaptionData* new_data = EDT_NewTableCaptionData();
  5900.     EDT_InsertTableCaption(context, new_data);
  5901.     EDT_FreeTableCaptionData(new_data);
  5902.     fe_EditorUpdateToolbar(context, 0);
  5903. }
  5904.  
  5905. Boolean
  5906. fe_EditorTableCaptionCanDelete(MWContext* context)
  5907. {
  5908.     return (EDT_IsInsertPointInTableCaption(context) != 0);
  5909. }
  5910.  
  5911. void
  5912. fe_EditorTableCaptionDelete(MWContext* context)
  5913. {
  5914.     if (EDT_IsInsertPointInTableCaption(context) != 0) {
  5915.     EDT_DeleteTableCaption(context);
  5916.     fe_EditorUpdateToolbar(context, 0);
  5917.     }
  5918. }
  5919.  
  5920. Boolean
  5921. fe_EditorTableColumnCanInsert(MWContext* context)
  5922. {
  5923.     return (EDT_IsInsertPointInTableRow(context) != 0);
  5924. }
  5925.  
  5926. void
  5927. fe_EditorTableColumnInsert(MWContext* context, EDT_TableCellData* data)
  5928. {
  5929.     EDT_TableCellData* new_data = EDT_NewTableCellData();
  5930.     EDT_InsertTableColumns(context, new_data, TRUE, 1);
  5931.     EDT_FreeTableCellData(new_data);
  5932.  
  5933.     fe_EditorUpdateToolbar(context, 0);
  5934. }
  5935.  
  5936. Boolean
  5937. fe_EditorTableColumnCanDelete(MWContext* context)
  5938. {
  5939.     return (EDT_IsInsertPointInTableRow(context) != 0);
  5940. }
  5941.  
  5942. void
  5943. fe_EditorTableColumnDelete(MWContext* context)
  5944. {
  5945.     if (EDT_IsInsertPointInTableRow(context) != 0) {
  5946.     EDT_DeleteTableColumns(context, 1);
  5947.     fe_EditorUpdateToolbar(context, 0);
  5948.     }
  5949. }
  5950.  
  5951. Boolean
  5952. fe_EditorTableCellCanInsert(MWContext* context)
  5953. {
  5954.     return (EDT_IsInsertPointInTableRow(context) != 0);
  5955. }
  5956.  
  5957. void
  5958. fe_EditorTableCellInsert(MWContext* context, EDT_TableCellData* data)
  5959. {
  5960.     EDT_TableCellData* new_data = EDT_NewTableCellData();
  5961.     EDT_InsertTableCells(context, new_data, TRUE, 1);
  5962.     EDT_FreeTableCellData(new_data);
  5963.  
  5964.     fe_EditorUpdateToolbar(context, 0);
  5965. }
  5966.  
  5967. Boolean
  5968. fe_EditorTableCellCanDelete(MWContext* context)
  5969. {
  5970.     return (EDT_IsInsertPointInTableCell(context) != 0);
  5971. }
  5972.  
  5973. void
  5974. fe_EditorTableCellDelete(MWContext* context)
  5975. {
  5976.     if (EDT_IsInsertPointInTableRow(context) != 0) {
  5977.     EDT_DeleteTableCells(context, 1);
  5978.     fe_EditorUpdateToolbar(context, 0);
  5979.     }
  5980. }
  5981.  
  5982. Boolean
  5983. fe_EditorTableCellGetData(MWContext* context, EDT_TableCellData* p_data)
  5984. {
  5985.     EDT_TableCellData* cell_data = EDT_GetTableCellData(context);
  5986.     if (cell_data) {
  5987.     *p_data = *cell_data;
  5988.     if (cell_data->pColorBackground != NULL) {
  5989.         static LO_Color color_buf;
  5990.         color_buf = *cell_data->pColorBackground;
  5991.         p_data->pColorBackground = &color_buf; /*caller cannot hang on*/
  5992.     }
  5993.     EDT_FreeTableCellData(cell_data);
  5994.     return TRUE;
  5995.     } else {
  5996.     return FALSE;
  5997.     }
  5998. }
  5999.  
  6000. void
  6001. fe_EditorTableCellSetData(MWContext* context, EDT_TableCellData* p_data)
  6002. {
  6003.     EDT_TableCellData* cell_data = EDT_GetTableCellData(context);
  6004.     if (cell_data) {
  6005.     COPY_SAVE_EXTRA(cell_data, p_data);
  6006.     DUP_BGCOLOR(cell_data, p_data);
  6007.     EDT_SetTableCellData(context, cell_data);
  6008.     EDT_FreeTableCellData(cell_data);
  6009.     fe_EditorUpdateToolbar(context, 0);
  6010.     }
  6011. }
  6012.  
  6013. void
  6014. fe_EditorPublish(MWContext* context)
  6015. {
  6016.     /* Get the destination and what files to include from the user:*/
  6017.     fe_EditorPublishDialogDo(context);
  6018. }
  6019.  
  6020. void
  6021. fe_EditorDisplayTablesSet(MWContext* context, Boolean display)
  6022. {
  6023.     EDT_SetDisplayTables(context, display == TRUE);
  6024.     fe_EditorUpdateToolbar(context, 0);
  6025. }
  6026.  
  6027. Boolean
  6028. fe_EditorDisplayTablesGet(MWContext* context)
  6029. {
  6030.     return (EDT_GetDisplayTables(context) == TRUE);
  6031. }
  6032.  
  6033. static char*
  6034. fe_action_name(char* buf,
  6035.            XtActionsRec* action_list,
  6036.            Cardinal      action_list_size,
  6037.            XtActionProc  action_proc,
  6038.            String *av, Cardinal *ac)
  6039. {
  6040.     int i;
  6041.     char* name = XP_GetString(XFE_UNKNOWN); /* "<unknown>" */
  6042.  
  6043.     if (action_list_size == 0)
  6044.     action_list_size = 100000; /* look for null termination */
  6045.  
  6046.     /*
  6047.      *    Look for action name in the action_list.
  6048.      */
  6049.     for (i = 0; i < action_list_size && action_list[i].string != NULL; i++) {
  6050.     if (action_list[i].proc == action_proc) {
  6051.         name = action_list[i].string;
  6052.         break;
  6053.     }
  6054.     }
  6055.  
  6056.     strcpy(buf, name);
  6057.     strcat(buf, "(");
  6058.     for (i = 0; i < *ac; i++) {
  6059.     if (i != 0)
  6060.         strcat(buf, ",");
  6061.     strcat(buf, av[i]);
  6062.     }
  6063.     strcat(buf, ")");
  6064.  
  6065.     return buf;
  6066. }
  6067.  
  6068. void xfe_GetShiftAndCtrl(XEvent* event, Boolean* shiftP, Boolean* ctrlP)
  6069. {
  6070.     if (event->type == KeyPress || event->type == KeyRelease) {
  6071.         unsigned int mask = event->xkey.state;
  6072.         if (shiftP) *shiftP = ((mask & ShiftMask) != 0);
  6073.         if (ctrlP) *ctrlP = ((mask & ControlMask) != 0);
  6074.     }
  6075.     else if (event->type == ButtonPress || event->type == ButtonRelease) {
  6076.         unsigned int mask = event->xbutton.state;
  6077.         if (shiftP) *shiftP = ((mask & ShiftMask) != 0);
  6078.         if (ctrlP) *ctrlP = ((mask & ControlMask) != 0);
  6079.     }
  6080. }
  6081.  
  6082. /*
  6083.  * NOTE:  because of this routine and its explicit need to disown the
  6084.  *        primary selection, we can't select text in the editor and then
  6085.  *        middle mouse paste it into another location in the same window...
  6086.  *
  6087.  *        - any ideas on how we might get around this one?...
  6088.  *
  6089.  *        :-l
  6090.  *
  6091.  */
  6092. void
  6093. fe_EditorGrabFocus(MWContext* context, XEvent *event)
  6094. {
  6095.     Widget da = NULL;
  6096.     XEvent ev;
  6097.   unsigned long x, y;
  6098.   Time time;
  6099.     LO_Element*   leHit = 0;
  6100.     ED_HitType    iTableHit; 
  6101.  
  6102. #ifdef DREDD_EDITOR
  6103.   fe_UserActivity(context); /* tell the app who has focus */
  6104. #else
  6105.  
  6106.     da = CONTEXT_DATA(context)->drawing_area;
  6107.  
  6108.     ev.type              = FocusIn;
  6109.     ev.xfocus.type       = FocusIn;
  6110.     ev.xfocus.send_event = False;
  6111.     ev.xfocus.display    = XtDisplay(da);
  6112.     ev.xfocus.window     = XtWindow(da);
  6113.     ev.xfocus.mode       = NotifyNormal;
  6114.     ev.xfocus.detail     = NotifyDetailNone;
  6115.  
  6116.     XtDispatchEvent(&ev);
  6117.  
  6118.     XSync(XtDisplay(da), False);
  6119.  
  6120.     /*
  6121.     XtSetKeyboardFocus(CONTEXT_WIDGET(context), da);
  6122.     */
  6123. #endif
  6124.  
  6125.   /* don't do this -- Japanese input method requires focus
  6126.   fe_NeutralizeFocus(context);
  6127.   */
  6128.  
  6129.   time = fe_getTimeFromEvent(context, event); /* get the time */
  6130.  
  6131.   fe_EventLOCoords(context, event, &x, &y); /* get the doc co-ords */
  6132.  
  6133.   /*
  6134.    *    Do this first, so the EDT_ClearSelection() in the call doesn't
  6135.    *    blow away what EDT_StartSelection() does!
  6136.    *
  6137.    */
  6138.   fe_EditorDisownSelection(context, time, False); /* give up selection */
  6139.  
  6140.   /* see if we're in a table first... */
  6141.   iTableHit = EDT_GetTableHitRegion(context, x, y, &leHit, False);
  6142.   if ( iTableHit != ED_HIT_NONE )
  6143.   {
  6144.       Boolean shift, ctrl;
  6145.       xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6146.  
  6147.       EDT_SelectTableElement(context, x, y,
  6148.                              leHit, iTableHit,
  6149.                              ctrl,      /* bModifierKeyPressed */
  6150.                              FALSE);    /*bExtendSelection*/
  6151.                            /*shift);    -*bExtendSelection*/
  6152.       return;
  6153.   }
  6154.   /* for some reason, EDT_GetTableHitRegion returns ED_HIT_NONE in a cell */
  6155.   else if (leHit && leHit->type == LO_CELL)
  6156.   {
  6157.       Boolean shift, ctrl;
  6158.       xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6159.  
  6160.       EDT_SelectTableElement(context, x, y,
  6161.                              leHit, ED_HIT_SEL_CELL,
  6162.                              ctrl,      /* bModifierKeyPressed */
  6163.                              shift);    /*bExtendSelection*/
  6164.       return;
  6165.   }
  6166.  
  6167.   EDT_StartSelection(context, x, y);
  6168. }
  6169.  
  6170. void
  6171. fe_EditorSelectionBegin(MWContext* context, XEvent *event)
  6172. {
  6173.     unsigned long x, y;
  6174.     Time time;
  6175.     LO_Element*   leHit = 0;
  6176.     ED_HitType    iTableHit; 
  6177.  
  6178.     /* don't do this -- Japanese input method requires focus
  6179.     fe_NeutralizeFocus (context);
  6180.      */
  6181.  
  6182.     if (CONTEXT_DATA(context)->editor.ascroll_data.timer_id) {
  6183.         XtRemoveTimeOut(CONTEXT_DATA(context)->editor.ascroll_data.timer_id);
  6184.         CONTEXT_DATA(context)->editor.ascroll_data.timer_id = 0;
  6185.     }
  6186.  
  6187.     if (CONTEXT_DATA(context)->clicking_blocked
  6188.         || CONTEXT_DATA (context)->synchronous_url_dialog)
  6189.     {
  6190.         fe_Bell(context);
  6191.         return;
  6192.     }
  6193.  
  6194.     time = fe_getTimeFromEvent(context, event); /* get the time */
  6195.   
  6196.     fe_EventLOCoords(context, event, &x, &y);
  6197.  
  6198. #ifdef DONT_rhess
  6199.     /* 
  6200.      *  WARNING... [ nuke the primary selection owner ]
  6201.      */
  6202.     {
  6203.         Display *dpy = XtDisplay(CONTEXT_WIDGET(context));
  6204.         Window  owner = XGetSelectionOwner(dpy, XA_PRIMARY);
  6205.  
  6206.         if (owner != None) {
  6207.             XSetSelectionOwner(dpy, XA_PRIMARY, None, time);
  6208.         }
  6209.     }
  6210. #endif
  6211.  
  6212.     /*
  6213.      *    Do this first, so the EDT_ClearSelection() in the call doesn't
  6214.      *    blow away what EDT_StartSelection() does!
  6215.      */
  6216.     fe_EditorDisownSelection(context, time, False);
  6217.  
  6218.     /* see if we're in a table first... */
  6219.     iTableHit = EDT_GetTableHitRegion(context, x, y, &leHit, False);
  6220.     if ( iTableHit != ED_HIT_NONE )
  6221.     {
  6222.         Boolean shift, ctrl;
  6223.         xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6224.         EDT_SelectTableElement(context, x, y,
  6225.                                leHit, iTableHit,
  6226.                                ctrl,    /* bModifierKeyPressed */
  6227.                                shift);  /*bExtendSelection*/
  6228.         return;
  6229.     }
  6230.     /* for some reason, EDT_GetTableHitRegion returns ED_HIT_NONE in a cell */
  6231.     else if (leHit && leHit->type == LO_CELL)
  6232.     {
  6233.         Boolean shift, ctrl;
  6234.         xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6235.  
  6236.         EDT_SelectTableElement(context, x, y,
  6237.                                leHit, ED_HIT_SEL_CELL,
  6238.                                ctrl,      /* bModifierKeyPressed */
  6239.                                shift);    /*bExtendSelection*/
  6240.         return;
  6241.     }
  6242.  
  6243.     else
  6244.         /* need to implement disown */
  6245.         EDT_StartSelection(context, x, y);
  6246. }
  6247.  
  6248. void
  6249. fe_EditorSelectionExtend(MWContext* context, XEvent *event)
  6250. {
  6251.     Time       time;
  6252.     unsigned long x;
  6253.     unsigned long y;
  6254.     LO_Element*   leHit = 0;
  6255.     ED_HitType    iTableHit; 
  6256.  
  6257.     time = fe_getTimeFromEvent(context, event); /* get the time */
  6258.  
  6259.     /* don't do this -- Japanese input method requires focus
  6260.      fe_NeutralizeFocus(context);
  6261.      */
  6262.  
  6263.     fe_EventLOCoords (context, event, &x, &y);
  6264.  
  6265.     if (CONTEXT_DATA(context)->editor.ascroll_data.timer_id) {
  6266.         XtRemoveTimeOut(CONTEXT_DATA(context)->editor.ascroll_data.timer_id);
  6267.         CONTEXT_DATA(context)->editor.ascroll_data.timer_id = 0;
  6268.     }
  6269.  
  6270.     fe_editor_keep_pointer_visible(context, x, y);
  6271.  
  6272. #ifdef DONT_rhess
  6273.     /* 
  6274.      *  WARNING... [ nuke the primary selection owner ]
  6275.      */
  6276.     {
  6277.         Display  *dpy = XtDisplay(CONTEXT_WIDGET(context));
  6278.         Window  owner = XGetSelectionOwner(dpy, XA_PRIMARY);
  6279.  
  6280.         if (owner != None) {
  6281.             XSetSelectionOwner(dpy, XA_PRIMARY, None, time);
  6282.         }
  6283.     }
  6284. #endif
  6285.  
  6286.     /* see if we're in a table first... */
  6287.     iTableHit = EDT_GetTableHitRegion(context, x, y, &leHit, False);
  6288.  
  6289.     if (leHit && leHit->type == LO_CELL)
  6290.     {
  6291.         Boolean shift, ctrl;
  6292.         xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6293.  
  6294.         EDT_SelectTableElement(context, x, y,
  6295.                                leHit, ED_HIT_SEL_CELL,
  6296.                                ctrl,      /* bModifierKeyPressed */
  6297.                                TRUE);    /*bExtendSelection*/
  6298.         return;
  6299.     }
  6300.  
  6301.     /* need to implement own */
  6302.     EDT_ExtendSelection(context, x, y);
  6303.  
  6304. #ifdef DONT_rhess
  6305.     fe_EditorOwnSelection (context, time, False, False);
  6306. #endif
  6307.  
  6308. #if 0
  6309.     /* Making a selection turns off "Save Next" mode. */
  6310.     if (CONTEXT_DATA (context)->save_next_mode_p)
  6311.         {
  6312.             XBell (XtDisplay (widget), 0);
  6313.             CONTEXT_DATA (context)->save_next_mode_p = False;
  6314.             fe_SetCursor (context, False);
  6315.             XFE_Progress (context, fe_globalData.click_to_save_cancelled_message);
  6316.         }
  6317. #endif
  6318. }
  6319.  
  6320. void
  6321. fe_EditorSelectionEnd(MWContext *context, XEvent *event)
  6322. {
  6323.     Time time;
  6324.     unsigned long x;
  6325.     unsigned long y;
  6326.     LO_Element*   leHit = 0;
  6327.     ED_HitType    iTableHit; 
  6328.  
  6329.     fe_UserActivity(context);
  6330.     time = fe_getTimeFromEvent(context, event); /* get the time */
  6331.  
  6332.     fe_EventLOCoords (context, event, &x, &y);
  6333.  
  6334.     if (CONTEXT_DATA(context)->editor.ascroll_data.timer_id) {
  6335.         XtRemoveTimeOut(CONTEXT_DATA(context)->editor.ascroll_data.timer_id);
  6336.         CONTEXT_DATA(context)->editor.ascroll_data.timer_id = 0;
  6337.     }
  6338.  
  6339.     /* see if we're in a table first... */
  6340.     iTableHit = EDT_GetTableHitRegion( context, x, y, &leHit, FALSE );
  6341.     if ( iTableHit == ED_HIT_SEL_TABLE
  6342.         || iTableHit == ED_HIT_SEL_ALL_CELLS
  6343.         || iTableHit == ED_HIT_SEL_COL
  6344.         || iTableHit == ED_HIT_SEL_ROW )
  6345.     {
  6346.         Boolean shift, ctrl;
  6347.         xfe_GetShiftAndCtrl(event, &shift, &ctrl);
  6348.         EDT_SelectTableElement(context, x, y,
  6349.                                leHit, iTableHit,
  6350.                                ctrl,    /* bModifierKeyPressed */
  6351.                                shift);  /*bExtendSelection*/
  6352.         return;
  6353.     }
  6354.  
  6355.     /* need to implement own */
  6356.     EDT_EndSelection(context, x, y);
  6357.  
  6358.     fe_EditorOwnSelection(context, time, False, False);
  6359. }
  6360.  
  6361. #define XFE_EDITOR_MAX_INSERT_SIZE 512
  6362.  
  6363. void
  6364. fe_EditorKeyInsert(MWContext* context, Widget widget, XEvent* event)
  6365. {
  6366.     char       buf[XFE_EDITOR_MAX_INSERT_SIZE + 1];
  6367.     KeySym     keysym;
  6368.     Status     status_return;
  6369.     int        len;
  6370.     EDT_ClipboardResult result = EDT_COP_OK;
  6371.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  6372.  
  6373.     if (widget != CONTEXT_DATA(context)->drawing_area) {
  6374. #ifdef DEBUG
  6375.         (void) fprintf(real_stderr,
  6376.                        "fe_editor_key_input_action got wrong widget (%s)\n",
  6377.                        XtName(widget));
  6378. #endif /* DEBUG */
  6379.         XtSetKeyboardFocus(CONTEXT_WIDGET(context),
  6380.                            CONTEXT_DATA(context)->drawing_area);
  6381.         return;
  6382.     }
  6383.     len = XmImMbLookupString(widget,
  6384.                              (XKeyEvent *)event,
  6385.                              buf,
  6386.                              XFE_EDITOR_MAX_INSERT_SIZE, 
  6387.                              &keysym,
  6388.                              &status_return);
  6389.     
  6390.     if (status_return == XBufferOverflow || len > XFE_EDITOR_MAX_INSERT_SIZE)
  6391.         return;
  6392.  
  6393.     if (len > 0) {
  6394.         char *str;
  6395.  
  6396.         buf[len] = 0;
  6397.         str = (char *) fe_ConvertFromLocaleEncoding(INTL_GetCSIWinCSID(c),
  6398.                                                     (unsigned char *) buf);
  6399.         if (str != buf) {
  6400.             len = strlen(str);
  6401.         }
  6402.  
  6403.         if (len == 1) {
  6404.             result = EDT_KeyDown(context, str[0], 0, 0);
  6405.         } else if (len > 1) {
  6406.             result = EDT_PasteText(context, str);
  6407.         }
  6408.  
  6409.         if (result != EDT_COP_OK) {
  6410.             fe_editor_report_copy_error(context, result);
  6411.         }
  6412.  
  6413.         if (str != buf && str != NULL) {
  6414.             XP_FREE(str);
  6415.         }
  6416.     }
  6417. }
  6418.  
  6419. void
  6420. fe_EditorTab(MWContext* context, Boolean forward, Boolean force)
  6421. {
  6422.     EDT_ClipboardResult result = EDT_TabKey(context, forward, force);
  6423.     
  6424.     if (result != EDT_COP_OK)
  6425.         fe_editor_report_copy_error(context, result);
  6426. }
  6427.  
  6428. /*
  6429.  *    Editor specific action handlers.
  6430.  */
  6431. static void
  6432. fe_ActionWrongContextAlert(MWContext*, XtActionProc, String*, Cardinal*);
  6433.  
  6434. #ifdef DEBUG
  6435. #define FE_ACTION_ALERT(c, p, a, n) fe_ActionWrongContextAlert((c),(p),(a),(n))
  6436. #else
  6437. #define FE_ACTION_ALERT(c, p, a, n)
  6438. #endif
  6439.  
  6440. #define FE_ACTION_VALIDATE(proc)                  \
  6441. if (!(context) || !EDT_IS_EDITOR(context)) {      \
  6442.     FE_ACTION_ALERT(context, (proc), av, ac);     \
  6443.     return;                                       \
  6444. }
  6445.  
  6446.  
  6447. #define FE_SYNTAX_ERROR(proc) fe_ActionSyntaxAlert(context, (proc), av, ac)
  6448.  
  6449. /*=========================== ACTIONS =================================*/
  6450. static void
  6451. fe_get_selected_text_rect(MWContext* context,
  6452.               LO_TextStruct* text,
  6453.               int32*         rect_x,
  6454.               int32*         rect_y,
  6455.               int32*         rect_width,
  6456.               int32*         rect_height)
  6457. {
  6458.     PA_Block    text_save = text->text;
  6459.     int         len_save = text->text_len;
  6460.     LO_TextInfo info;
  6461.     
  6462.     text->text_len = text->sel_start;
  6463.     XFE_GetTextInfo(context, text, &info);
  6464.  
  6465.     *rect_x = text->x + text->x_offset + info.max_width;
  6466.     *rect_y = text->y + text->y_offset;
  6467.  
  6468.     text->text = (PA_Block)((char*)text->text + text->sel_start);
  6469.     text->text_len = text->sel_end - text->sel_start;
  6470.     
  6471.     XFE_GetTextInfo(context, text, &info);
  6472.  
  6473.     *rect_width = info.max_width;
  6474.     *rect_height = info.ascent + info.descent;
  6475.  
  6476.     text->text = text_save;
  6477.     text->text_len = len_save;
  6478. }
  6479.  
  6480. static Boolean
  6481. fe_editor_selection_contains_point(MWContext* context, int32 x, int32 y)
  6482. {
  6483.     int32 start_selection;
  6484.     int32 end_selection;
  6485.     LO_Element* start_element = NULL;
  6486.     LO_Element* end_element = NULL;
  6487.     LO_Element* lo_element;
  6488.     int32 rect_x;
  6489.     int32 rect_y;
  6490.     int32 rect_width;
  6491.     int32 rect_height;
  6492.     CL_Layer *layer;
  6493.  
  6494.     if (!EDT_IsSelected(context))
  6495.     return FALSE;
  6496.  
  6497.     LO_GetSelectionEndpoints(context,
  6498.                  &start_element,
  6499.                  &end_element,
  6500.                  &start_selection,
  6501.                  &end_selection,
  6502.                              &layer);
  6503.  
  6504.     if (start_element == NULL)
  6505.     return FALSE;
  6506.  
  6507.     for (lo_element = start_element;
  6508.      lo_element != NULL;
  6509.      lo_element = ((LO_Any *)lo_element)->next) {
  6510.  
  6511.     if (lo_element->type == LO_TEXT &&
  6512.         (lo_element == start_element || lo_element == end_element)) {
  6513.         LO_TextStruct* text = (LO_TextStruct*)lo_element;
  6514.  
  6515.         if (text->text == NULL) {
  6516.         if (text->prev != NULL && text->prev->type == LO_TEXT) {
  6517.             text = (LO_TextStruct*)text->prev;
  6518.         } else {
  6519.             text = (LO_TextStruct*)text->next;
  6520.         }
  6521.         }
  6522.         
  6523.         if (text->text == NULL)
  6524.         continue;
  6525.         
  6526.         fe_get_selected_text_rect(context, text,
  6527.                       &rect_x,
  6528.                       &rect_y,
  6529.                       &rect_width,
  6530.                       &rect_height);
  6531.         
  6532.     } else if (lo_element->type == LO_LINEFEED) {
  6533.         continue;
  6534.         
  6535.     } else {
  6536.         LO_Any* lo_any = (LO_Any*)lo_element;
  6537.         rect_x = lo_any->x + lo_any->x_offset;
  6538.         rect_y = lo_any->y + lo_any->y_offset;
  6539.         rect_width = lo_any->width;
  6540.         rect_height = lo_any->height;
  6541.     }
  6542.     
  6543.     if (x > rect_x && y > rect_y &&
  6544.         x < (rect_x + rect_width) && y < (rect_y + rect_height))
  6545.         return TRUE;
  6546.  
  6547.     if (lo_element == end_element)
  6548.         break;
  6549.     }
  6550.  
  6551.     return FALSE;
  6552. }
  6553.  
  6554. Boolean
  6555. fe_EditorSelectionContainsPoint(MWContext* context, int32 x, int32 y)
  6556. {
  6557.     return fe_editor_selection_contains_point(context, x, y);
  6558. }
  6559.  
  6560. static char*
  6561. fe_lo_image_anchor(LO_ImageStruct* image,
  6562.              long x, long y,
  6563.              MWContext* context)
  6564. {
  6565.     if (image->is_icon &&
  6566.         image->icon_number == IL_IMAGE_DELAYED) { /* delayed image */ 
  6567.         long width, height;
  6568.  
  6569.         fe_IconSize(IL_IMAGE_DELAYED, &width, &height);
  6570.  
  6571.         if (image->alt &&
  6572.             image->alt_len &&
  6573.             (x > image->x + image->x_offset + 1 + 4 + width)) {
  6574.             if (image->anchor_href) {
  6575.                 return (char *)image->anchor_href->anchor;
  6576.             }
  6577.         } /* else fall to end */
  6578.     } 
  6579.  
  6580.     /*
  6581.      *    Internal editor image maybe?
  6582.      */
  6583.     else if (image->is_icon &&
  6584.              (image->icon_number == IL_EDIT_NAMED_ANCHOR ||
  6585.               image->icon_number == IL_EDIT_FORM_ELEMENT ||
  6586.               image->icon_number == IL_EDIT_UNSUPPORTED_TAG ||
  6587.               image->icon_number == IL_EDIT_UNSUPPORTED_END_TAG)) {
  6588.  
  6589.         if (image->alt != NULL)
  6590.             return (char*)image->alt;
  6591.         else
  6592.             return "";
  6593.     }
  6594.  
  6595.     /*
  6596.      * This would be a client-side usemap image.
  6597.      */
  6598.     else if (image->image_attr->usemap_name != NULL) {
  6599.     
  6600.         LO_AnchorData *anchor_href;
  6601.         long ix = image->x + image->x_offset;
  6602.         long iy = image->y + image->y_offset;
  6603.         long mx = x - ix - image->border_width;
  6604.         long my = y - iy - image->border_width;
  6605.     
  6606.         anchor_href = LO_MapXYToAreaAnchor(context,
  6607.                                            (LO_ImageStruct *)image,
  6608.                                            mx, my);
  6609.         if (anchor_href) {
  6610.             return (char *)anchor_href->anchor;
  6611.         } /* else fall to end */
  6612.     } else { /* some old random image */
  6613.         if (image->anchor_href) {
  6614.             return (char *)image->anchor_href->anchor;
  6615.         }
  6616.     }
  6617.  
  6618.     return NULL;
  6619. }
  6620.  
  6621. static LO_Element*   fe_editor_motion_action_last_le;
  6622. static Boolean       fe_editor_motion_action_last_le_is_image;
  6623. static LO_Element*   fe_editor_motion_action_last_hit_le;
  6624. static ED_HitType    fe_editor_motion_action_last_hit_type;
  6625.  
  6626. static void
  6627. fe_editor_motion_action(Widget widget, XEvent *event,
  6628.             String *av, Cardinal *ac)
  6629. {
  6630.     MWContext*    context = fe_MotionWidgetToMWContext(widget);
  6631.     LO_Element*   le;
  6632.     LO_Element*   leHit;
  6633.     ED_HitType    iTableHit; 
  6634.     unsigned long x, y;
  6635.     Cursor        cursor = None;
  6636.     char*         progress_string = NULL;
  6637.     char buf[80];
  6638.     char num[32];
  6639.  
  6640.     FE_ACTION_VALIDATE(fe_editor_motion_action);
  6641.  
  6642.     fe_EventLOCoords(context, event, &x, &y); /* get the doc co-ords */
  6643.  
  6644.     /* NOTE:  let's see if we're in table stuff first... */
  6645.     iTableHit = EDT_GetTableHitRegion( context, 
  6646.                                        x, y, 
  6647.                                        &leHit,
  6648.                                        FALSE );
  6649.     if ( iTableHit ) { 
  6650.         if ((fe_editor_motion_action_last_hit_type == iTableHit) &&
  6651.             (fe_editor_motion_action_last_hit_le == leHit)) {
  6652.             return;  /* NOTE:  no change... */
  6653.         }
  6654.  
  6655.         fe_editor_motion_action_last_hit_le   = leHit;
  6656.         fe_editor_motion_action_last_hit_type = iTableHit;
  6657.  
  6658.         switch ( iTableHit ) { 
  6659.             case ED_HIT_SEL_TABLE:
  6660. #ifdef DEBUG_motion
  6661.                 fprintf(stderr, "ED_HIT_SEL_TABLE:\n");
  6662. #endif
  6663.                 cursor = CONTEXT_DATA(context)->tab_sel_cursor;
  6664.                 break; 
  6665.  
  6666.             case ED_HIT_SEL_ALL_CELLS: 
  6667. #ifdef DEBUG_motion
  6668.                 fprintf(stderr, "ED_HIT_SEL_ALL_CELLS:\n");
  6669. #endif
  6670.                 cursor = None;
  6671.                 break; 
  6672.  
  6673.             case ED_HIT_SEL_COL:  
  6674. #ifdef DEBUG_motion
  6675.                 fprintf(stderr, "ED_HIT_SEL_COL:\n");
  6676. #endif
  6677.                 cursor = CONTEXT_DATA(context)->col_sel_cursor;
  6678.                 break; 
  6679.  
  6680.             case ED_HIT_SEL_ROW:  
  6681. #ifdef DEBUG_motion
  6682.                 fprintf(stderr, "ED_HIT_SEL_ROW:\n");
  6683. #endif
  6684.                 cursor = CONTEXT_DATA(context)->row_sel_cursor;
  6685.                 break; 
  6686.  
  6687.             case ED_HIT_SEL_CELL:  
  6688. #ifdef DEBUG_motion
  6689.                 fprintf(stderr, "ED_HIT_SEL_CELL:\n");
  6690. #endif
  6691.                 cursor = CONTEXT_DATA(context)->cel_sel_cursor;
  6692.                 break; 
  6693.  
  6694. #ifdef ED_HIT_SIZE_TABLE
  6695.             case ED_HIT_SIZE_TABLE:  
  6696. #ifdef DEBUG_motion
  6697.                 fprintf(stderr, "ED_HIT_SIZE_TABLE:\n");
  6698. #endif
  6699.                 cursor = CONTEXT_DATA(context)->resize_tab_cursor;
  6700.                 break; 
  6701. #endif /* ED_HIT_SIZE_TABLE */
  6702.  
  6703.             case ED_HIT_SIZE_COL:  
  6704. #ifdef DEBUG_motion
  6705.                 fprintf(stderr, "ED_HIT_SIZE_COL:\n");
  6706. #endif
  6707.                 cursor = CONTEXT_DATA(context)->resize_col_cursor;
  6708.                 break;
  6709.  
  6710.             case ED_HIT_ADD_ROWS:  
  6711. #ifdef DEBUG_motion
  6712.                 fprintf(stderr, "ED_HIT_ADD_ROWS:\n");
  6713. #endif
  6714.                 cursor = CONTEXT_DATA(context)->add_row_cursor;
  6715.                 break; 
  6716.  
  6717.             case ED_HIT_ADD_COLS:  
  6718. #ifdef DEBUG_motion
  6719.                 fprintf(stderr, "ED_HIT_ADD_COLS:\n");
  6720. #endif
  6721.                 cursor = CONTEXT_DATA(context)->add_col_cursor;
  6722.                 break; 
  6723.  
  6724.             default:  
  6725.                 /* NOTE:  we shouldn't ever get here... */
  6726. #ifdef DEBUG_motion
  6727.                 fprintf(stderr, "fe_editor_motion_action default:  WARNING ***************\n");
  6728. #endif
  6729.                 cursor = None;
  6730.         } 
  6731.     } 
  6732.     else {
  6733.         /* NOTE:  let's check for the other elements... */
  6734.  
  6735.         le = LO_XYToElement(context, (int32)x, (int32)y, NULL);
  6736.  
  6737.         if (le == fe_editor_motion_action_last_le &&
  6738.             !fe_editor_motion_action_last_le_is_image &&
  6739.             (fe_editor_motion_action_last_hit_type == 0)) {
  6740.             return; /* NOTE:  no change... */
  6741.         }
  6742.  
  6743.         fe_editor_motion_action_last_hit_le   = NULL;
  6744.         fe_editor_motion_action_last_hit_type = 0;
  6745.  
  6746.         fe_editor_motion_action_last_le_is_image = FALSE;
  6747.         fe_editor_motion_action_last_le = le;
  6748.     
  6749.         if (le != NULL) {
  6750.             /*  Are we over text? Special cursor */
  6751.             if (le->type == LO_TEXT) {
  6752.                 cursor = CONTEXT_DATA(context)->editable_text_cursor;
  6753.                 if (le->lo_text.anchor_href) { /* link */
  6754.                     progress_string = (char *)le->lo_text.anchor_href->anchor;
  6755.                 }
  6756.                 /*  Over image, special progress */
  6757.             } 
  6758.             else {
  6759.                 if (le->type == LO_IMAGE) {
  6760.                     progress_string = fe_lo_image_anchor(&le->lo_image, 
  6761.                                                          /* link ? */
  6762.                                                          x, y,
  6763.                                                          context);
  6764.                     if (progress_string != NULL && progress_string[0] == '\0')
  6765.                         progress_string = NULL;
  6766.                     
  6767.                     if (progress_string == NULL) {
  6768.                         
  6769.                         if (le->lo_image.image_url) {
  6770.                             progress_string = (char*)le->lo_image.image_url;
  6771.                         } else if (le->lo_image.lowres_image_url) {
  6772.                             progress_string = (char*)le->lo_image.lowres_image_url;
  6773.                         }
  6774.                     
  6775.                         if (progress_string != NULL) {
  6776.                             sprintf(num, ",%d,%d",
  6777.                                     x - le->lo_image.x, y - le->lo_image.y);
  6778.                             FE_CondenseURL(buf, progress_string,
  6779.                                            sizeof(buf) - 1 - strlen(num));
  6780.                             strcat(buf, num);
  6781.                             progress_string = buf;
  6782.                             fe_editor_motion_action_last_le_is_image = TRUE;
  6783.                         }
  6784.                     }
  6785.                 }
  6786.             }
  6787.         }
  6788.     }
  6789.  
  6790.     if (CONTEXT_DATA(context)->clicking_blocked ||
  6791.         CONTEXT_DATA(context)->synchronous_url_dialog) {
  6792.         cursor = CONTEXT_DATA(context)->busy_cursor;
  6793.     }
  6794.  
  6795.     if (CONTEXT_DATA(context)->drawing_area) {
  6796.         XDefineCursor(XtDisplay(CONTEXT_DATA(context)->drawing_area),
  6797.                       XtWindow(CONTEXT_DATA(context)->drawing_area),
  6798.                       cursor);
  6799.     }
  6800.  
  6801.     if (progress_string == NULL)
  6802.         progress_string = "";
  6803.  
  6804.     if (CONTEXT_DATA(context)->active_url_count == 0) {
  6805.         /* If there are transfers in progress, don't document the URL under
  6806.            the mouse, since that message would interfere with the transfer
  6807.            messages.  Do change the cursor, however. */
  6808.         fe_MidTruncatedProgress(context, progress_string);
  6809.     }
  6810. }
  6811.  
  6812. #define EA_PREFIX "editor-"
  6813.  
  6814. static XtActionsRec fe_editor_actions [] =
  6815. {
  6816.     { EA_PREFIX "motion", fe_editor_motion_action },
  6817. };
  6818.  
  6819. static void
  6820. fe_ActionWrongContextAlert(MWContext*    context,
  6821.                XtActionProc  action_proc,
  6822.                String* av, Cardinal* ac)
  6823. {
  6824.     char buf[1024];
  6825.     char name[1024];
  6826.  
  6827.     fe_action_name(name,
  6828.            fe_editor_actions, countof(fe_editor_actions),
  6829.            action_proc, av, ac);
  6830.     sprintf(buf, XP_GetString(XFE_ACTION_WRONG_CONTEXT), name);
  6831.  
  6832.     if (context)
  6833.     FE_Alert(context, buf);
  6834.     else
  6835.     fprintf(real_stderr, buf);
  6836. }
  6837.  
  6838. void
  6839. fe_EditorInitActions()
  6840. {
  6841.     XtAppAddActions(fe_XtAppContext,
  6842.                     fe_editor_actions,
  6843.                     countof(fe_editor_actions)
  6844.                     );
  6845. }
  6846.  
  6847. static void
  6848. fe_EditURLCallback(const char* urlToOpen)
  6849. {
  6850.     /*
  6851.      *    Try to get editor first.  XP_FindSomeContext() does not look for
  6852.      *    editor context.
  6853.      */
  6854.     MWContext *context = XP_FindContextOfType(NULL, MWContextEditor);
  6855.     if (!context) {
  6856.         context = XP_FindSomeContext();
  6857.     }
  6858.  
  6859.     /* This shouldn't happen. */
  6860.     if (!context) {
  6861.         XP_ASSERT(0);
  6862.         return;
  6863.     }
  6864.  
  6865.     /*
  6866.      *   If urlToOpen is already being edited, this will just pop it to
  6867.      *   front.
  6868.      */
  6869.     fe_EditorEdit(context, NULL, NULL, (char*)urlToOpen);
  6870. }
  6871.  
  6872. void
  6873. fe_EditorStaticInit()
  6874. {
  6875.     EDTPLUG_RegisterEditURLCallback(&fe_EditURLCallback);
  6876. }
  6877.  
  6878. /*
  6879.  * Note: this routine is untested.  It's called for dragging columns,
  6880.  * not for highlighting selected columns.
  6881.  */
  6882. void
  6883. FE_DisplayAddRowOrColBorder(MWContext* context, XP_Rect *pRect,
  6884.                             XP_Bool bErase)
  6885. {
  6886.     XGCValues gcv;
  6887.     unsigned long gc_flags;
  6888.     GC gc;
  6889.     fe_Drawable *fe_drawable = CONTEXT_DATA(context)->drawable;
  6890.  
  6891. #ifdef DEBUG_akkana
  6892.     printf("FE_DisplayAddRowOrColBorder\n");
  6893. #endif /* DEBUG_akkana */
  6894.  
  6895.     if (bErase)
  6896.     {
  6897.         gc_flags = GCForeground /* | GCLineWidth */ | GCLineStyle;
  6898.         gcv.foreground = CONTEXT_DATA(context)->select_bg_pixel;
  6899.     }
  6900.     else
  6901.     {
  6902.         gc_flags = GCForeground /* | GCLineWidth */ | GCLineStyle;
  6903.         gcv.foreground = CONTEXT_DATA(context)->select_bg_pixel;
  6904.         gcv.line_style = LineOnOffDash;
  6905.     }
  6906.     /*gcv.line_width = iSelectionBorderThickness;*/
  6907.     gc = fe_GetGCfromDW(fe_display, fe_drawable->xdrawable,
  6908.                         gc_flags, &gcv, fe_drawable->clip_region);
  6909.     XDrawRectangle(fe_display,
  6910.                    XtWindow(CONTEXT_DATA(context)->drawing_area), gc,
  6911.                    pRect->left, pRect->top,
  6912.                    pRect->left - pRect->right, pRect->bottom - pRect->top);
  6913. }
  6914.  
  6915. void 
  6916. FE_DisplayEntireTableOrCell(MWContext* context, LO_Element* pLoElement)
  6917. {
  6918.     LO_TableStruct* table;
  6919.  
  6920.     if (pLoElement->lo_any.type == LO_TABLE)
  6921.     {
  6922.         XFE_DisplayTable(context, 0, &(pLoElement->lo_table));
  6923.     }
  6924.     else if (pLoElement->lo_any.type == LO_CELL)
  6925.     {
  6926.         XFE_DisplayCell(context, 0, &(pLoElement->lo_cell));
  6927.     }
  6928.     else        /* shouldn't happen */
  6929.     {
  6930. #ifdef DEBUG_akkana
  6931.         printf("FE_DisplayEntireTableOrCell() with type %d\n",
  6932.                pLoElement->lo_any.type);
  6933. #endif /* DEBUG_akkana */
  6934.         table = lo_GetParentTable(context, pLoElement);
  6935.         XFE_DisplayTable(context, 0, table);
  6936.     }
  6937. }
  6938.  
  6939.  
  6940. #endif /* EDITOR */
  6941.