blob: 0f8521a258c21305e25ddef46d43a56fbc2a4d03 [file] [log] [blame]
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1999-2017 The R Core Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.R-project.org/Licenses/
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "win-nls.h"
#ifdef Win32
#define USE_MDI 1
#endif
#include <Defn.h>
#include <Fileio.h>
#include <stdio.h>
#include <Startup.h>
#include "graphapp/ga.h"
#include "graphapp/graphapp.h"
#include "graphapp/stdimg.h"
#include "console.h"
#include "consolestructs.h"
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include "rui.h"
#include "editor.h"
/* from sysutils.c */
void reEnc2(const char *x, char *y, int ny,
cetype_t ce_in, cetype_t ce_out, int subst);
#define gettext GA_gettext
#define MCHECK(a) if (!(a)) {del(c); return NULL;}
RECT *RgetMDIsize(void);
/* Pointers to currently open editors */
static editor REditors[MAXNEDITORS];
static int neditors = 0;
static Rboolean fix_editor_up = FALSE;
static EditorData neweditordata (int file, const char *filename)
{
EditorData p;
p = (EditorData) malloc(sizeof(struct structEditorData));
p->file = file;
/* need space for terminator, and to copy it */
p->filename = (char *) malloc((MAX_PATH+1)*sizeof(char));
if (filename)
strncpy(p->filename, filename, MAX_PATH+1);
p->title = (char *) malloc((EDITORMAXTITLE + 1)*sizeof(char));
p->title[EDITORMAXTITLE] = p->title[0] = '\0';
return p;
}
void deleditordata(EditorData p)
{
if (p->stealconsole)
fix_editor_up = FALSE;
free(p->filename);
free(p->title);
free(p->hmenu);
free(p->pmenu);
free(p);
}
static void editor_set_title(editor c, const char *title)
{
char wtitle[EDITORMAXTITLE+1];
textbox t = getdata(c);
EditorData p = getdata(t);
strncpy(wtitle, title, EDITORMAXTITLE);
wtitle[EDITORMAXTITLE] = '\0';
strcpy(p->title, wtitle);
if (strlen(wtitle) + strlen(G_("R Editor")) + 3 < EDITORMAXTITLE) {
strcat(wtitle, " - ");
strcat(wtitle, G_("R Editor"));
}
settext(c, wtitle);
}
/*** FILE MANAGEMENT FUNCTIONS ***/
FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode);
static void editor_load_file(editor c, const char *name, int enc)
{
textbox t = getdata(c);
EditorData p = getdata(t);
FILE *f;
char *buffer = NULL, tmp[MAX_PATH+50], tname[MAX_PATH+1];
const char *sname;
long num = 1, bufsize;
if(enc == CE_UTF8) {
wchar_t wname[MAX_PATH+1];
Rf_utf8towcs(wname, name, MAX_PATH+1);
f = R_wfopen(wname, L"r");
reEnc2(name, tname, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
sname = tname;
} else {
f = R_fopen(name, "r");
sname = name;
}
if (f == NULL) {
snprintf(tmp, MAX_PATH+50,
G_("unable to open file %s for reading"), sname);
R_ShowMessage(tmp);
return;
}
p->file = 1;
strncpy(p->filename, name, MAX_PATH+1);
bufsize = 0;
while (num > 0) {
buffer = realloc(buffer, bufsize + 3000 + 1);
num = fread(buffer + bufsize, 1, 3000 - 1, f);
if (num >= 0) {
bufsize += num;
buffer[bufsize] = '\0';
}
else {
snprintf(tmp, MAX_PATH+50,
G_("Could not read from file '%s'"), sname);
askok(tmp);
}
}
setlimittext(t, 2 * strlen(buffer));
settext(t, buffer);
gsetmodified(t, 0);
free(buffer);
fclose(f);
}
static void editor_save_file(editor c, const char *name, int enc)
{
textbox t = getdata(c);
FILE *f;
char buf[MAX_PATH+30], tname[MAX_PATH+1];
const char *sname;
if (name == NULL)
return;
else {
if(enc == CE_UTF8) {
wchar_t wname[MAX_PATH+1];
Rf_utf8towcs(wname, name, MAX_PATH+1);
reEnc2(name, tname, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
sname = tname;
f = R_wfopen(wname, L"w");
} else {
sname = name;
f = R_fopen(sname, "w");
}
if (f == NULL) {
snprintf(buf, MAX_PATH+30, G_("Could not save file '%s'"), sname);
askok(buf);
return;
}
fprintf(f, "%s", gettext(t));
fclose(f);
}
}
static void editorsaveas(editor c)
{
textbox t = getdata(c);
EditorData p = getdata(t);
wchar_t *wname;
setuserfilterW(L"R files (*.R)\0*.R\0S files (*.q, *.ssc, *.S)\0*.q;*.ssc;*.S\0All files (*.*)\0*.*\0\0");
wname = askfilesaveW(G_("Save script as"), "");
if (wname) {
char name[4*MAX_PATH+1];
wcstoutf8(name, wname, sizeof(name));
/* now check if it has an extension */
char *q = strchr(name, '.');
if(!q) strncat(name, ".R", 4*MAX_PATH);
editor_save_file(c, name, CE_UTF8);
p->file = 1;
reEnc2(name, p->filename, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
gsetmodified(t, 0);
editor_set_title(c, p->filename);
}
show(c);
}
static void menueditorsaveas(control m)
{
editor c = getdata(m);
editorsaveas(c);
}
static void editorsave(editor c)
{
textbox t = getdata(c);
EditorData p = getdata(t);
if (p->file) { /* save existing file without prompt */
editor_save_file(c, p->filename, CE_UTF8);
gsetmodified(t, 0);
}
/* if new file then prompt for name to save as */
else editorsaveas(c);
}
static void menueditorsave(control m)
{
editor c = getdata(m);
editorsave(c);
show(c); /* steal focus back from tool button */
}
/* global console configuration variables */
char fontname[LF_FACESIZE+1];
int fontsty, pointsize;
static void editorprint(control m)
{
printer lpr;
font f;
textbox t = getdata(m);
const char *contents = gettext(t);
char msg[LF_FACESIZE + 128];
char *linebuf = NULL;
int cc, rr, fh, page, linep, i, j, istartline;
int top, left;
if (!(lpr = newprinter(0.0, 0.0, ""))) return;
f = gnewfont(lpr, strcmp(fontname, "FixedFont") ? fontname : "Courier New",
fontsty, pointsize, 0.0, 1);
top = devicepixelsy(lpr) / 5;
left = devicepixelsx(lpr) / 5;
fh = fontheight(f);
rr = getheight(lpr) - top;
cc = getwidth(lpr) - 2*left;
linep = rr; /* line in printer page */
page = 1;
i = 0;
while (i < strlen(contents)) {
if ( linep + fh >= rr ) { /* new page */
if (page > 1) nextpage(lpr);
snprintf(msg, LF_FACESIZE + 128, "Page %d", page++);
gdrawstr(lpr, f, Black, pt(cc - gstrwidth(lpr, f, msg) - 1, top),
msg);
linep = top + 2*fh;
}
j = 0;
istartline = i;
while (contents[i] != '\n' && contents[i] != '\0') {
++i; ++j;
}
linebuf = realloc(linebuf, (j+1)*sizeof(char));
strncpy(linebuf, &contents[istartline], j);
linebuf[j] = '\0';
gdrawstr(lpr, f, Black, pt(left, linep), linebuf);
linep += fh;
++i;
}
free(linebuf);
if (f != FixedFont) del(f);
del(lpr);
}
static void editorconsole(editor c)
{
show(RConsole);
}
/* Remove global pointer to editor when closing an editor. Fill the
* gap in the array with the last editor in the list */
static void editorupdateglobals(editor c)
{
int i = 0;
if (neditors > 1) {
while (REditors[i] != c) ++i;
if (i < neditors - 1)
REditors[i] = REditors[neditors-1];
}
--neditors;
}
/* Hooks called when editor window is destroyed */
static void editordel(editor c)
{
editorupdateglobals(c);
}
static void textboxdel(textbox t)
{
EditorData p = getdata(t);
deleditordata(p);
}
int editorchecksave(editor c)
{
textbox t = getdata(c);
EditorData p = getdata(t);
int save;
char buf[EDITORMAXTITLE + 100];
if (ggetmodified(t)) {
snprintf(buf, EDITORMAXTITLE + 100,
"\"%s\" has been modified. Do you want to save the changes?",
(p->title ? p->title : "Untitled"));
save = askyesnocancel(buf);
switch (save) {
case YES:
editorsave(c);
break;
case NO:
break;
case CANCEL:
return 1;
}
}
return 0;
}
static void editorclose(editor c)
{
if (!editorchecksave(c))
del(c);
}
static void menueditorclose(control m)
{
editor c = getdata(m);
editorclose(c);
}
/* Called when exiting Rgui, check if any open editors need saving */
void editorcleanall(void)
{
int i;
for (i = neditors-1; i >= 0; --i) {
if (editorchecksave(REditors[i])) {
R_ProcessEvents(); // see R_CleanUp
jump_to_toplevel();
}
del(REditors[i]);
}
}
static void editornew(void)
{
Rgui_Edit("", CE_NATIVE, "", 0);
}
void menueditornew(control m)
{
editornew();
}
static void editoropen(const char *default_name)
{
wchar_t *wname;
char name[4*MAX_PATH + 1], title[4*MAX_PATH];
int i; textbox t; EditorData p;
setuserfilterW(L"R files (*.R)\0*.R\0S files (*.q, *.ssc, *.S)\0*.q;*.ssc;*.S\0All files (*.*)\0*.*\0\0");
wname = askfilenameW(G_("Open script"), default_name); /* returns NULL if open dialog cancelled */
if (wname) {
wcstoutf8(name, wname, sizeof(name));
/* check if file is already open in an editor. If so, close and open again */
for (i = 0; i < neditors; ++i) {
t = getdata(REditors[i]);
p = getdata(t);
if (!strcmp (name, p->filename)) {
editorclose(REditors[i]);
break;
}
}
reEnc2(name, title, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
Rgui_Edit(name, CE_UTF8, title, 0);
} else show(RConsole);
}
void menueditoropen(control m)
{
editor c = getdata(m);
char *default_name = "";
/* It really is not clear what is meant here: seems to assume an
editor window but is called from elsewhere, hopefully with NULL
(since 2.1.1 patched). */
if (c) {
textbox t = getdata(c);
EditorData p = getdata(t);
if (p->file) default_name = p->filename; /* name of currently-open file, if there is one */
}
editoropen(default_name);
}
/*** EDITING FUNCTIONS ***/
static void editorundo(control m)
{
textbox t = getdata(m);
undotext(t);
}
static void editorcut(control m)
{
textbox t = getdata(m);
cuttext(t);
}
static void editorcopy(control m)
{
textbox t = getdata(m);
copytext(t);
}
static void editorpaste(control m)
{
textbox t = getdata(m);
/* check whether the widget text limit needs to be increased
* before doing the paste */
int pastelen = getpastelength();
checklimittext(t, pastelen + 1);
pastetext(t);
}
static void editordelete(control m)
{
textbox t = getdata(m);
cleartext(t);
}
static void editorselectall(control m)
{
textbox t = getdata(m);
selecttextex(t, 0, -1);
}
static void editorfind(control m)
{
textbox t = getdata(m);
finddialog(t); /* actual find/replace work is in graphapp/dialogs.c */
}
static void editorreplace(control m)
{
textbox t = getdata(m);
replacedialog(t);
}
/*** FUNCTIONS FOR RUNNING R CODE FROM THE EDITOR ***/
static void editorrunline(textbox t)
{
int length = getlinelength(t); /* return character num */
char *line = malloc(length * sizeof(WCHAR) + 2); /* Extra space for null and word length in getcurrentline */
memset(line, 0, length * sizeof(WCHAR) + 2);
getcurrentline(t, line, length);
consolecmd(RConsole, line);
free(line);
scrollcaret(t, 1);
show(t);
}
/* For the moment, send the selected text to the console via the
clipboard. Wasteful, but currently consolecmd only allows a maximum
of 8K of text */
static void editorrunselection(textbox t, long start, long end)
{
copytext(t);
if (consolecanpaste(RConsole)) {
consolepaste(RConsole);
if (gettext(t)[end-1] != '\n')
consolenewline(RConsole);
}
}
static Rboolean busy_running = FALSE;
static void editorrun(textbox t)
{
if (!busy_running) {
long start=0, end=0;
if (CharacterMode != RGui) {
R_ShowMessage(G_("No RGui console to paste to"));
return;
}
busy_running = TRUE;
textselectionex(t, &start, &end);
if (start >= end)
editorrunline(t);
else {
editorrunselection(t, start, end);
selecttextex(t, end, end); /* move insertion point to end of selection after running */
}
busy_running = FALSE;
}
}
static void menueditorrun(control m)
{
textbox t = getdata(m);
editorrun(t);
}
static void editorrunall(control m)
{
textbox t = getdata(m);
long start=0, end=0;
textselectionex(t, &start, &end); /* save current selection state */
selecttextex(t, 0, -1);
editorrun(t);
selecttextex(t, start, end); /* return to original selection state */
}
/* Grey out menu buttons as appropriate */
static void editormenuact(control m)
{
long start, end;
textbox t = getdata(m);
EditorData p = getdata(t);
textselectionex(t, &start, &end);
if (start < end) {
enable(p->mcut);
enable(p->mcopy);
enable(p->mdelete);
enable(p->mpopcut);
enable(p->mpopcopy);
enable(p->mpopdelete);
}
else {
disable(p->mcut);
disable(p->mcopy);
disable(p->mdelete);
disable(p->mpopcut);
disable(p->mpopcopy);
disable(p->mpopdelete);
}
if (modeless_active()){
disable(p->mfind);
disable(p->mreplace);
}
else {
enable(p->mfind);
enable(p->mreplace);
}
helpmenuact(p->hmenu);
pkgmenuact(p->pmenu);
}
static void editorresize(editor c, rect r)
{
resize(getdata(c), r);
resize(c, r);
}
static void editorcontrolkeydown(textbox t, int key)
{
switch (key) {
case F5:
editorrun(t);
break;
}
}
static void editorasciikeydown(textbox t, int key)
{
/* check whether the text limit is about to be exceeded and
increase it if necessary. Ugh - this callback is called after
the text is inserted, so we make space for two characters */
checklimittext(t, 2);
}
/* Set keyboard focus to the text editing area when the editor window receives focus */
static void editorfocus(editor c)
{
textbox t = getdata(c);
show(t);
}
static void editorhelp(void)
{
char s[4096];
strcpy(s, G_("R EDITOR\n"));
strcat(s, "\n");
strcat(s, G_("A standard text editor for editing and running R code.\n"));
strcat(s, "\n");
strcat(s, G_("RUNNING COMMANDS\n"));
strcat(s, G_("To run a line or section of R code, select the code and either\n"));
strcat(s, G_(" Press Ctrl-R\n"));
strcat(s, G_(" Select \"Run line or selection\" from the \"Edit\" menu\n"));
strcat(s, G_(" Press the \"Run line or selection\" icon on the toolbar\n"));
strcat(s, G_("This will copy the selected commands to the console and evaluate them.\n"));
strcat(s, G_("If there is no selection, this will just run the current line and advance\n"));
strcat(s, G_("the cursor by one line.\n"));
askok(s);
}
static void menueditorhelp(control m)
{
editorhelp();
}
static MenuItem EditorPopup[] = { /* Numbers used below */
{GN_("Run line or selection"), menueditorrun, 'R', 0}, /* 0 */
{"-", 0, 0, 0},
{GN_("Undo"), editorundo, 'Z', 0}, /* 2 */
{"-", 0, 0, 0},
{GN_("Cut"), editorcut, 'X', 0}, /* 4 */
{GN_("Copy"), editorcopy, 'C', 0}, /* 5 */
{GN_("Paste"), editorpaste, 'V', 0}, /* 6 */
{GN_("Delete"), editordelete, 0, 0}, /* 7 */
{"-", 0, 0, 0},
{GN_("Select all"), editorselectall, 'A', 0}, /* 9 */
LASTMENUITEM
};
static editor neweditor(void)
{
int x, y, w, h, w0, h0;
editor c;
menuitem m;
textbox t;
long flags;
font editorfn = (consolefn ? consolefn : FixedFont);
EditorData p = neweditordata(0, NULL);
DWORD rand;
w = (pagercol + 1)*fontwidth(editorfn);
h = (pagerrow + 1)*fontheight(editorfn) + 1;
#ifdef USE_MDI
if(ismdi()) {
RECT *pR = RgetMDIsize();
w0 = pR->right;
h0 = pR->bottom;
} else {
#endif
w0 = devicewidth(NULL);
h0 = deviceheight(NULL);
#ifdef USE_MDI
}
#endif
x = (w0 - w) / 2; x = x > 20 ? x : 20;
y = (h0 - h) / 2; y = y > 20 ? y : 20;
rand = GetTickCount();
w0 = 0.4*x; h0 = 0.4*y;
w0 = w0 > 20 ? w0 : 20;
h0 = h0 > 20 ? h0 : 20;
x += (rand % w0) - w0/2;
y += ((rand/w0) % h0) - h0/2;
flags = StandardWindow | Menubar;
#ifdef USE_MDI
if (ismdi()) flags |= Document;
#endif
c = (editor) newwindow("", rect(x, y, w, h), flags);
t = newrichtextarea(NULL, rect(0, 0, w, h));
setdata(c, t);
setdata(t, p);
gsetcursor(c, ArrowCursor);
setforeground(c, guiColors[editorfg]);
setbackground(c, guiColors[editorbg]);
setbackground(t, guiColors[editorbg]);
#ifdef USE_MDI
if (ismdi() && (RguiMDI & RW_TOOLBAR)) {
int btsize = 24;
rect r = rect(2, 2, btsize, btsize);
control tb, bt;
addto(c);
MCHECK(tb = newtoolbar(btsize + 4));
addto(tb);
MCHECK(bt = newtoolbutton(open_image, r, menueditoropen));
MCHECK(addtooltip(bt, G_("Open script")));
setdata(bt, c);
r.x += (btsize + 1) ;
MCHECK(bt = newtoolbutton(save_image, r, menueditorsave));
MCHECK(addtooltip(bt, G_("Save script")));
setdata(bt, c);
r.x += (btsize + 6);
MCHECK(bt = newtoolbutton(copy1_image, r, menueditorrun));
MCHECK(addtooltip(bt, G_("Run line or selection")));
setdata(bt, t);
r.x += (btsize + 6);
MCHECK(bt = newtoolbutton(console_image, r, editorconsole));
MCHECK(addtooltip(bt, G_("Return focus to Console")));
r.x += (btsize + 6);
MCHECK(bt = newtoolbutton(print_image, r, editorprint));
MCHECK(addtooltip(bt, G_("Print script")));
setdata(bt, t);
MCHECK(addtooltip(bt, G_("Print")));
}
#endif
addto(c);
/* Right-click context menu */
MCHECK(m = gpopup(editormenuact, EditorPopup));
setdata(m, t);
setdata(EditorPopup[0].m, t);
setdata(EditorPopup[2].m, t);
setdata(p->mpopcut = EditorPopup[4].m, t);
setdata(p->mpopcopy = EditorPopup[5].m, t);
setdata(EditorPopup[6].m, t);
setdata(p->mpopdelete = EditorPopup[7].m, t);
setdata(EditorPopup[9].m, t);
addto(c);
MCHECK(m = newmenubar(editormenuact));
setdata(m, t);
MCHECK(newmenu(G_("File")));
MCHECK(m = newmenuitem(G_("New script"), 'N', menueditornew));
setdata(m, c);
MCHECK(m = newmenuitem(G_("Open script..."), 'O', menueditoropen));
setdata(m, c);
MCHECK(m = newmenuitem(G_("Save"), 'S', menueditorsave));
setdata(m, c);
MCHECK(m = newmenuitem(G_("Save as..."), 0, menueditorsaveas));
setdata(m, c);
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(m = newmenuitem(G_("Print..."), 'P', editorprint));
setdata(m, t);
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(m = newmenuitem(G_("Close script"), 0, menueditorclose));
setdata(m, c);
MCHECK(newmenu(G_("Edit")));
MCHECK(m = newmenuitem(G_("Undo"), 'Z', editorundo));
setdata(m, t);
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(p->mcut = newmenuitem(G_("Cut"), 'X', editorcut));
setdata(p->mcut, t);
MCHECK(p->mcopy = newmenuitem(G_("Copy"), 'C', editorcopy));
setdata(p->mcopy, t);
MCHECK(m = newmenuitem(G_("Paste"), 'V', editorpaste));
setdata(m, t);
MCHECK(p->mdelete = newmenuitem(G_("Delete"), 0, editordelete));
setdata(p->mdelete, t);
MCHECK(m = newmenuitem(G_("Select all"), 'A', editorselectall));
setdata(m, t);
MCHECK(newmenuitem(G_("Clear console"), 'L', menuclear));
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(m = newmenuitem(G_("Run line or selection"), 'R', menueditorrun));
setdata(m, t);
MCHECK(m = newmenuitem(G_("Run all"), 0, editorrunall));
setdata(m, t);
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(p->mfind = newmenuitem(G_("Find..."), 'F', editorfind));
setdata(p->mfind, t);
MCHECK(p->mreplace = newmenuitem(G_("Replace..."), 'H', editorreplace));
setdata(p->mreplace, t);
MCHECK(m = newmenuitem("-", 0, NULL));
MCHECK(newmenuitem(G_("GUI preferences..."), 0, menuconfig));
/* Packages menu should go here */
p->pmenu = (PkgMenuItems) malloc(sizeof(struct structPkgMenuItems));
RguiPackageMenu(p->pmenu);
#ifdef USE_MDI
newmdimenu(); /* Create and fill the 'Window' menu */
#endif
MCHECK(m = newmenu(G_("Help")));
MCHECK(newmenuitem(G_("Editor"), 0, menueditorhelp));
MCHECK(newmenuitem("-", 0, NULL));
p->hmenu = (HelpMenuItems) malloc(sizeof(struct structHelpMenuItems));
RguiCommonHelp(m, p->hmenu);
settextfont(t, editorfn);
setforeground(t, guiColors[editorfg]);
setresize(c, editorresize);
setclose(c, editorclose);
setdel(c, editordel);
setdel(t, textboxdel);
setonfocus(c, editorfocus);
setkeyaction(t, editorcontrolkeydown);
setkeydown(t, editorasciikeydown);
/* Store pointer to new editor in global array */
REditors[neditors] = c;
++neditors;
return c;
}
/* Change the font used in all running editors */
void editorsetfont(font f)
{
int i, ismod;
textbox t;
for (i = 0; i < neditors; i++) {
t = getdata(REditors[i]);
ismod = ggetmodified(t);
/* Don't change the modification flag when changing font */
settextfont(t, f);
gsetmodified(t, ismod);
show(t);
}
}
static void eventloop(editor c)
{
while (fix_editor_up) {
/* avoid consuming 100% CPU time here */
R_WaitEvent();
R_ProcessEvents();
}
}
/* Open existing file for editing or open blank editor for a new
file. If calling from fix() or edit(), then don't send events to
the console until editor is closed. */
#include <unistd.h>
int Rgui_Edit(const char *filename, int enc, const char *title,
int modal)
{
editor c;
EditorData p;
if (neditors == MAXNEDITORS) {
R_ShowMessage(G_("Maximum number of editors reached"));
return 1;
}
c = neweditor();
if (!c) {
R_ShowMessage(G_("Unable to create editor window"));
return 1;
}
if (strlen(filename) > 0) {
editor_load_file(c, filename, enc);
editor_set_title(c, title);
}
else {
editor_set_title(c, G_("Untitled"));
}
show(c);
p = getdata(getdata(c));
p->stealconsole = modal;
if (modal) {
fix_editor_up = TRUE;
eventloop(c);
}
return 0;
}