qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs archive.c dired.c image.c shell.c bufed....


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs archive.c dired.c image.c shell.c bufed....
Date: Thu, 27 Aug 2015 15:32:29 +0000

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        15/08/27 15:32:29

Modified files:
        .              : archive.c dired.c image.c shell.c bufed.c 
                         docbook.c qe.c video.c buffer.c html.c qe.h 

Log message:
        modes: upgrade mode selection and handling
        - separate buffer and window specific mode data management, new API:
           QEModeData *qe_create_buffer_mode_data(EditBuffer *b, ModeDef *m);
           void *qe_get_buffer_mode_data(EditBuffer *b, ModeDef *m, EditState 
*e);
           QEModeData *qe_create_window_mode_data(EditState *s, ModeDef *m);
           void *qe_get_window_mode_data(EditState *e, ModeDef *m, int status);
           int qe_free_mode_data(QEModeData *md);
        - make a list of buffer specific mode data areas so multiple major 
modes 
          can co-exist in different windows for the same buffer
        - add mode.mode_free callback to release buffer specific resources
        - remove buffer.close callback
        - shell state is now buffer specific shell_mode data
        - clean up compress and archive mode
        - show more buffer modes in buffer-list
        - simplify edit_set_mode(), display error message on failure

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/archive.c?cvsroot=qemacs&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/qemacs/dired.c?cvsroot=qemacs&r1=1.58&r2=1.59
http://cvs.savannah.gnu.org/viewcvs/qemacs/image.c?cvsroot=qemacs&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/qemacs/shell.c?cvsroot=qemacs&r1=1.100&r2=1.101
http://cvs.savannah.gnu.org/viewcvs/qemacs/bufed.c?cvsroot=qemacs&r1=1.39&r2=1.40
http://cvs.savannah.gnu.org/viewcvs/qemacs/docbook.c?cvsroot=qemacs&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.c?cvsroot=qemacs&r1=1.209&r2=1.210
http://cvs.savannah.gnu.org/viewcvs/qemacs/video.c?cvsroot=qemacs&r1=1.20&r2=1.21
http://cvs.savannah.gnu.org/viewcvs/qemacs/buffer.c?cvsroot=qemacs&r1=1.92&r2=1.93
http://cvs.savannah.gnu.org/viewcvs/qemacs/html.c?cvsroot=qemacs&r1=1.34&r2=1.35
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.h?cvsroot=qemacs&r1=1.206&r2=1.207

Patches:
Index: archive.c
===================================================================
RCS file: /sources/qemacs/qemacs/archive.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- archive.c   25 Aug 2015 16:19:42 -0000      1.21
+++ archive.c   27 Aug 2015 15:31:59 -0000      1.22
@@ -20,8 +20,11 @@
 
 #include "qe.h"
 
-/* Archivers */
-typedef struct ArchiveType {
+/*---------------- Archivers ----------------*/
+
+typedef struct ArchiveType ArchiveType;
+
+struct ArchiveType {
     const char *name;           /* name of archive format */
     const char *magic;          /* magic signature */
     int magic_size;
@@ -29,7 +32,7 @@
     const char *list_cmd;       /* list archive contents to stdout */
     const char *extract_cmd;    /* extract archive element to stdout */
     struct ArchiveType *next;
-} ArchiveType;
+};
 
 static ArchiveType archive_type_array[] = {
     { "tar", NULL, 0, "tar|tar.Z|tgz|tar.gz|tbz|tbz2|tar.bz2|tar.bzip2|"
@@ -48,34 +51,6 @@
 
 static ArchiveType *archive_types;
 
-/* Compressors */
-typedef struct CompressType {
-    const char *name;           /* name of compressed format */
-    const char *magic;          /* magic signature */
-    int magic_size;
-    const char *extensions;
-    const char *load_cmd;       /* uncompress file to stdout */
-    const char *save_cmd;       /* compress to file from stdin */
-    struct CompressType *next;
-} CompressType;
-
-static CompressType compress_type_array[] = {
-    { "gzip", NULL, 0, "gz", "gunzip -c $1", "gzip > $1" },
-    { "bzip2", NULL, 0, "bz2|bzip2", "bunzip2 -c $1", "bzip2 > $1" },
-    { "compress", NULL, 0, "Z", "uncompress -c $1", "compress > $1" },
-    { "LZMA", NULL, 0, "lzma", "unlzma -c $1", "lzma > $1" },
-    { "XZ", NULL, 0, "xz", "unxz -c $1", "xz > $1" },
-    { "BinHex", NULL, 0, "hqx", "binhex decode -o /tmp/qe-$$ $1 && "
-                       "cat /tmp/qe-$$ ; rm -f /tmp/qe-$$", NULL },
-    { "sqlite", "SQLite format 3\0", 16, NULL, "sqlite3 $1 .dump", NULL },
-    { "bplist", "bplist00", 8, "plist", "plutil -p $1", NULL },
-//    { "bplist", "bplist00", 8, "plist", "plutil -convert xml1 -o - $1", NULL 
},
-};
-
-static CompressType *compress_types;
-
-/*---------------- Archivers ----------------*/
-
 static ArchiveType *find_archive_type(const char *filename,
                                       const u8 *buf, int buf_size)
 {
@@ -99,9 +74,9 @@
     ArchiveType *atp = find_archive_type(p->filename, p->buf, p->buf_size);
 
     if (atp) {
-        if (p->b && p->b->priv_data) {
+        if (p->b && p->b->data_type == mode->data_type) {
             /* buffer loaded, re-selecting mode causes buffer reload */
-            return 9;
+            return 0;//9
         } else {
             /* buffer not yet loaded */
             return 85;//70
@@ -139,8 +114,6 @@
     return out->len;
 }
 
-static ModeDef archive_mode;
-
 static int file_read_block(EditBuffer *b, FILE *f1, u8 *buf, int buf_size)
 {
     FILE *f = f1;
@@ -205,6 +178,12 @@
     NULL, /* next */
 };
 
+static ModeDef archive_mode = {
+    .name = "archive",
+    .mode_probe = archive_mode_probe,
+    .data_type = &archive_data_type,
+};
+
 static int archive_init(void)
 {
     int i;
@@ -229,6 +208,33 @@
 
 /*---------------- Compressors ----------------*/
 
+typedef struct CompressType CompressType;
+
+struct CompressType {
+    const char *name;           /* name of compressed format */
+    const char *magic;          /* magic signature */
+    int magic_size;
+    const char *extensions;
+    const char *load_cmd;       /* uncompress file to stdout */
+    const char *save_cmd;       /* compress to file from stdin */
+    struct CompressType *next;
+};
+
+static CompressType compress_type_array[] = {
+    { "gzip", NULL, 0, "gz", "gunzip -c $1", "gzip > $1" },
+    { "bzip2", NULL, 0, "bz2|bzip2", "bunzip2 -c $1", "bzip2 > $1" },
+    { "compress", NULL, 0, "Z", "uncompress -c $1", "compress > $1" },
+    { "LZMA", NULL, 0, "lzma", "unlzma -c $1", "lzma > $1" },
+    { "XZ", NULL, 0, "xz", "unxz -c $1", "xz > $1" },
+    { "BinHex", NULL, 0, "hqx", "binhex decode -o /tmp/qe-$$ $1 && "
+                       "cat /tmp/qe-$$ ; rm -f /tmp/qe-$$", NULL },
+    { "sqlite", "SQLite format 3\0", 16, NULL, "sqlite3 $1 .dump", NULL },
+    { "bplist", "bplist00", 8, "plist", "plutil -p $1", NULL },
+//    { "bplist", "bplist00", 8, "plist", "plutil -convert xml1 -o - $1", NULL 
},
+};
+
+static CompressType *compress_types;
+
 static CompressType *find_compress_type(const char *filename,
                                         const u8 *buf, int buf_size)
 {
@@ -252,9 +258,9 @@
     CompressType *ctp = find_compress_type(p->filename, p->buf, p->buf_size);
 
     if (ctp) {
-        if (p->b && p->b->priv_data) {
+        if (p->b && p->b->data_type == mode->data_type) {
             /* buffer loaded, re-selecting mode causes buffer reload */
-            return 9;
+            return 0;//9;
         } else {
             /* buffer not yet loaded */
             return 82;
@@ -264,8 +270,6 @@
     return 0;
 }
 
-static ModeDef compress_mode;
-
 static int compress_buffer_load(EditBuffer *b, FILE *f)
 {
     /* Launch subprocess to expand compressed contents */
@@ -313,6 +317,12 @@
     NULL, /* next */
 };
 
+static ModeDef compress_mode = {
+    .name = "compress",
+    .mode_probe = compress_mode_probe,
+    .data_type = &compress_data_type,
+};
+
 static int compress_init(void)
 {
     int i;
@@ -344,7 +354,7 @@
     if (strstart(p->real_filename, "http:", NULL)
     ||  strstart(p->real_filename, "https:", NULL)
     ||  strstart(p->real_filename, "ftp:", NULL)) {
-        if (p->b && p->b->priv_data) {
+        if (p->b && p->b->data_type == mode->data_type) {
             /* buffer loaded, re-selecting mode causes buffer reload */
             return 9;
         } else {
@@ -430,7 +440,7 @@
          !memcmp(p->buf, "'''", 3) ||
          !memcmp(p->buf, "\\\"", 2))) {
     has_man:
-        if (p->b && p->b->priv_data) {
+        if (p->b && p->b->data_type == mode->data_type) {
             /* buffer loaded, re-selecting mode causes buffer reload */
             return 9;
         } else {

Index: dired.c
===================================================================
RCS file: /sources/qemacs/qemacs/dired.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -b -r1.58 -r1.59
--- dired.c     26 Aug 2015 01:12:21 -0000      1.58
+++ dired.c     27 Aug 2015 15:32:06 -0000      1.59
@@ -67,7 +67,7 @@
 #endif
 
 typedef struct DiredState {
-    ModeDef *signature;
+    QEModeData base;    /* derived from QEModeData */
     StringArray items;
     int sort_mode; /* DIRED_SORT_GROUP | DIRED_SORT_NAME */
     int last_index;
@@ -96,17 +96,9 @@
     char    name[1];
 } DiredItem;
 
-static DiredState *dired_get_state(EditState *s, int status)
+static inline DiredState *dired_get_state(EditState *e, int status)
 {
-    DiredState *ds = s->b->priv_data;
-
-    if (ds && ds->signature == &dired_mode)
-        return ds;
-
-    if (status)
-        put_status(s, "Not a dired buffer");
-
-    return NULL;
+    return qe_get_buffer_mode_data(e->b, &dired_mode, status ? e : NULL);
 }
 
 static inline int dired_get_index(EditState *s) {
@@ -976,7 +968,7 @@
     char filename[MAX_FILENAME_SIZE];
     int index;
 
-    if (!(ds = dired_get_state(s, 1)))
+    if (!(ds = dired_get_state(s, 0)))
         return;
 
     /* Prevent point from going beyond list */
@@ -1006,71 +998,49 @@
     }
 }
 
-static void dired_close(EditBuffer *b)
-{
-    DiredState *ds = b->priv_data;
-
-    if (ds && ds->signature == &dired_mode) {
-        dired_free(ds);
-    }
-
-    qe_free(&b->priv_data);
-    if (b->close == dired_close)
-        b->close = NULL;
-}
-
 static int dired_mode_init(EditState *s, EditBuffer *b, int flags)
 {
-    DiredState *ds;
+    DiredState *ds = qe_get_buffer_mode_data(b, &dired_mode, NULL);
 
-    list_mode.mode_init(s, b, flags);
-
-    if (s) {
-        if (s->b->priv_data) {
-            ds = s->b->priv_data;
-            if (ds->signature != &dired_mode)
-                return -1;
-        } else {
-            /* XXX: should be allocated by buffer_load API */
-            ds = qe_mallocz(DiredState);
             if (!ds)
                 return -1;
 
-            ds->signature = &dired_mode;
+    list_mode.mode_init(s, b, flags);
+
+    if (flags & MODEF_NEWINSTANCE) {
             /* XXX: Should use last sort mode, a global variable */
             ds->sort_mode = DIRED_SORT_GROUP | DIRED_SORT_NAME;
             ds->last_index = -1;
 
-            s->b->priv_data = ds;
-            s->b->close = dired_close;
-
             eb_create_style_buffer(b, BF_STYLE1);
             /* XXX: should be built by buffer_load API */
-            dired_build_list(ds, s->b->filename, NULL, s->b, s);
+        dired_build_list(ds, b->filename, NULL, b, s);
             /* XXX: File system charset should be detected automatically */
             /* XXX: If file system charset is not utf8, eb_printf will fail */
-            eb_set_charset(s->b, &charset_utf8, s->b->eol_type);
-        }
+        eb_set_charset(b, &charset_utf8, b->eol_type);
     }
     return 0;
 }
 
+static void dired_mode_free(EditBuffer *b, void *state)
+{
+    DiredState *ds = state;
+
+    dired_free(ds);
+}
+
 /* can only apply dired mode on directories */
 static int dired_mode_probe(ModeDef *mode, ModeProbeData *p)
 {
-    if (p->b->priv_data) {
-        DiredState *ds = p->b->priv_data;
-        if (ds->signature != &dired_mode)
-            return 0;
-        else
+    if (qe_get_buffer_mode_data(p->b, &dired_mode, NULL))
             return 100;
-    }
+
     if (S_ISDIR(p->st_mode))
         return 95;
-    else
+
     if (strchr(p->real_filename, '*') || strchr(p->real_filename, '?'))
         return 90;
-    else
+
         return 0;
 }
 
@@ -1196,7 +1166,9 @@
     memcpy(&dired_mode, &list_mode, sizeof(ModeDef));
     dired_mode.name = "dired";
     dired_mode.mode_probe = dired_mode_probe;
+    dired_mode.buffer_instance_size = sizeof(DiredState);
     dired_mode.mode_init = dired_mode_init;
+    dired_mode.mode_free = dired_mode_free;
     /* CG: not a good idea, display hook has side effect on layout */
     dired_mode.display_hook = dired_display_hook;
 

Index: image.c
===================================================================
RCS file: /sources/qemacs/qemacs/image.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- image.c     1 Jun 2014 13:54:59 -0000       1.28
+++ image.c     27 Aug 2015 15:32:09 -0000      1.29
@@ -23,25 +23,35 @@
 
 #define SCROLL_MHEIGHT     10
 
-typedef struct ImageBuffer {
+typedef struct ImageBuffer ImageBuffer;
+typedef struct ImageState ImageState;
+typedef struct ImageBufferState ImageBufferState;
+
+struct ImageBufferState {
+    QEModeData base;
+    ImageBuffer *ib;
+};
+
+struct ImageBuffer {
     int pix_fmt;
     int width;
     int height;
     int interleaved; /* just an info to tell if the image is interleaved */
     int alpha_info;  /* see FF_ALPHA_xxx constants */
     AVPicture pict; /* NOTE: data[] fields are temporary */
-} ImageBuffer;
+};
 
-typedef struct ImageState {
+struct ImageState {
+    QEModeData base;
+    ImageBufferState *ibs;
     QEBitmap *disp_bmp;
     int x, y; /* position of the center of the image in window */
     int w, h; /* displayed size */
     int xfactor_num, xfactor_den;
     int yfactor_num, yfactor_den;
+    /* XXX: should also have a current zone with mark(x/y) and cur(x/y) */
     QEColor background_color; /* transparent to display tiles */
-} ImageState;
-
-static EditBufferDataType image_data_type;
+};
 
 int qe_bitmap_format_to_pix_fmt(int format)
 {
@@ -89,6 +99,7 @@
     h2 = s->height - (y + h);
     if (h2 < 0)
         h2 = 0;
+
     fill_rectangle(s->screen,
                    s->xleft, s->ytop,
                    w1, s->height,
@@ -125,13 +136,21 @@
     }
 }
 
+static ImageState *image_get_state(EditState *e, int status)
+{
+    return qe_get_window_mode_data(e, &image_mode, status);
+}
+
 /* transp: 0x94 and 0x64, 16x16 grid */
 
 static void image_display(EditState *s)
 {
-    ImageState *is = s->mode_data;
+    ImageState *is = image_get_state(s, 0);
     int x, y;
 
+    if (!is)
+        return;
+
     if (s->display_invalid) {
         if (is->disp_bmp) {
             x = is->x + (s->width - is->w) / 2;
@@ -166,10 +185,15 @@
 /* resize current image using the current factors */
 static void image_resize(EditState *s)
 {
-    ImageState *is = s->mode_data;
-    ImageBuffer *ib = s->b->data;
+    ImageState *is = image_get_state(s, 1);
+    ImageBuffer *ib;
     int d, w, h;
 
+    if (!is)
+        return;
+
+    ib = is->ibs->ib;
+
     /* simplify factors */
     d = gcd(is->xfactor_num, is->xfactor_den);
     is->xfactor_num /= d;
@@ -190,8 +214,7 @@
         h = 1;
 
     /* if no resize needed, exit */
-    if (w == is->w &&
-        h == is->h)
+    if (w == is->w && h == is->h)
         return;
 
     edit_invalidate(s);
@@ -200,7 +223,10 @@
 
 static void image_normal_size(EditState *s)
 {
-    ImageState *is = s->mode_data;
+    ImageState *is = image_get_state(s, 1);
+
+    if (!is)
+        return;
 
     is->xfactor_num = 1;
     is->xfactor_den = 1;
@@ -214,7 +240,10 @@
 /* increase or decrease image size by percent */
 static void image_mult_size(EditState *s, int percent)
 {
-    ImageState *is = s->mode_data;
+    ImageState *is = image_get_state(s, 1);
+
+    if (!is)
+        return;
 
     is->xfactor_num *= (100 + percent);
     is->xfactor_den *= 100;
@@ -226,8 +255,13 @@
 
 static void image_set_size(EditState *s, int w, int h)
 {
-    ImageState *is = s->mode_data;
-    ImageBuffer *ib = s->b->data;
+    ImageState *is = image_get_state(s, 1);
+    ImageBuffer *ib;
+
+    if (!is)
+        return;
+
+    ib = is->ibs->ib;
 
     if (w < 1 || h < 1) {
         put_status(s, "Invalid image size");
@@ -258,6 +292,13 @@
         return 100;
 }
 
+static void image_mode_free(EditBuffer *b, void *state)
+{
+    ImageBufferState *ibs = state;
+
+    image_free(&ibs->ib);
+}
+
 /* allocate a new image at the end of the buffer */
 static ImageBuffer *image_allocate(int pix_fmt, int width, int height)
 {
@@ -286,24 +327,26 @@
     return ib;
 }
 
-static void image_free(ImageBuffer *ib)
+static void image_free(ImageBuffer **ibp)
 {
-    qe_free(&ib->pict.data[0]);
-    qe_free(&ib);
+    if (*ibp) {
+        qe_free(&(*ibp)->pict.data[0]);
+        qe_free(ibp);
+    }
 }
 
-
 static int read_image_cb(void *opaque, AVImageInfo *info)
 {
-    EditBuffer *b = opaque;
+    ImageBufferState *ibs = opaque;
     ImageBuffer *ib;
     int i;
 
     ib = image_allocate(info->pix_fmt, info->width, info->height);
     if (!ib)
         return AVERROR_NOMEM;
+
+    ibs->ib = ib;
     ib->interleaved = info->interleaved;
-    b->data = ib;
     for (i = 0; i < 4; i++) {
         info->pict.linesize[i] = ib->pict.linesize[i];
         info->pict.data[i] = ib->pict.data[i];
@@ -314,42 +357,61 @@
 static int image_buffer_load(EditBuffer *b, FILE *f)
 {
     ByteIOContext pb1, *pb = &pb1;
+    ImageBufferState *ibs;
     int ret;
 
+    ibs = qe_get_buffer_mode_data(b, &image_mode, NULL);
+    if (!ibs)
+        return;
+
     /* start loading the image */
     ret = url_fopen(pb, b->filename, URL_RDONLY);
     if (ret < 0)
         return -1;
 
-    ret = av_read_image(pb, b->filename, NULL, read_image_cb, b);
+    ret = av_read_image(pb, b->filename, NULL, read_image_cb, ibs);
     url_fclose(pb);
     if (ret) {
         return -1;
     } else {
-        ImageBuffer *ib = b->data;
+        ImageBuffer *ib = ibs->ib;
         ib->alpha_info = img_get_alpha_info(&ib->pict, ib->pix_fmt,
                                             ib->width, ib->height);
         return 0;
     }
 }
 
-static void set_new_image(EditBuffer *b, ImageBuffer *ib)
+static int set_new_image(EditBuffer *b, ImageBuffer *ib)
 {
-    b->data = ib;
+    ImageBufferState *ibs = qe_get_buffer_mode_data(b, &image_mode, NULL);
+
+    if (!ibs)
+        return -1;
+
+    image_free(&ibs->ib);
+    ibs->ib = ib;
+    /* XXX: should signal all windows that image changed? */
     eb_invalidate_raw_data(b);
-    b->modified = 1;
+    b->modified = 1;  /* not really */
+    return 0;
 }
 
 static int image_buffer_save(EditBuffer *b, int start, int end,
                              const char *filename)
 {
     ByteIOContext pb1, *pb = &pb1;
-    ImageBuffer *ib = b->data;
+    ImageBufferState *ibs = qe_get_buffer_mode_data(b, &image_mode, NULL);
+    ImageBuffer *ib;
     ImageBuffer *ib1 = NULL;
     int ret, dst_pix_fmt, loss;
     AVImageFormat *fmt;
     AVImageInfo info;
 
+    if (!ibs || !ibs->ib)
+        return -1;
+
+    ib = ibs->ib;
+
     /* find image format */
     fmt = guess_image_format(filename);
     if (!fmt)
@@ -360,17 +422,18 @@
                                             ib->pix_fmt, ib->alpha_info, 
&loss);
     if (dst_pix_fmt < 0)
         return -1;
+
     /* convert to new format if needed */
     if (dst_pix_fmt != ib->pix_fmt) {
         ib1 = image_allocate(dst_pix_fmt, ib->width, ib->height);
         if (!ib1)
             return -1;
         if (img_convert(&ib1->pict, ib1->pix_fmt,
-                        &ib->pict, ib->pix_fmt, ib->width, ib->height) < 0)
+                        &ib->pict, ib->pix_fmt, ib->width, ib->height) < 0) {
+            image_free(&ib1);
             return -1;
-
+        }
         set_new_image(b, ib1);
-        image_free(ib);
         ib = ib1;
     }
 
@@ -392,23 +455,28 @@
 
 static void image_buffer_close(EditBuffer *b)
 {
-    ImageBuffer *ib = b->data;
+    ImageBufferState *ibs = qe_get_buffer_mode_data(b, &image_mode, NULL);
 
-    image_free(ib);
-    b->data = NULL;
+    if (ibs) {
+        image_free(&ibs->ib);
+    }
 }
 
-
 static void update_bmp(EditState *s)
 {
-    ImageState *is = s->mode_data;
-    ImageBuffer *ib = s->b->data;
+    ImageState *is = image_get_state(s, 1);
+    ImageBuffer *ib;
     QEPicture pict;
     AVPicture avpict;
     ImageBuffer *ib1;
     int dst_pix_fmt;
     int i;
 
+    if (!is)
+        return;
+
+    ib = is->ibs->ib;
+
     bmp_free(s->screen, &is->disp_bmp);
 
     /* combine with the appropriate background if alpha is present */
@@ -487,9 +555,20 @@
 static int image_mode_init(EditState *s, EditBuffer *b, int flags)
 {
     if (s) {
-        ImageState *is = s->mode_data;
-        ImageBuffer *ib = s->b->data;
+        if (flags & MODEF_NEWINSTANCE) {
+            ImageState *is = qe_get_window_mode_data(s, &image_mode, 0);
+            ImageBufferState *ibs = qe_get_buffer_mode_data(b, &image_mode, 
NULL);
+            ImageBuffer *ib;
+
+            if (!ibs || !is)
+                return -1;
+
+            ib = qe_mallocz(ImageBuffer);
+            if (!ib)
+                return -1;
 
+            is->ibs = ibs;
+            ibs->ib = ib;
         is->w = ib->width;
         is->h = ib->height;
         is->xfactor_num = 1;
@@ -497,7 +576,7 @@
         is->yfactor_num = 1;
         is->yfactor_den = 1;
         is->background_color = 0; /* display tiles */
-
+        }
         update_bmp(s);
 
         eb_add_callback(s->b, image_callback, s, 1);
@@ -507,9 +586,12 @@
 
 static void update_pos(EditState *s, int dx, int dy)
 {
-    ImageState *is = s->mode_data;
+    ImageState *is = image_get_state(s, 1);
     int delta;
 
+    if (!is)
+        return;
+
     is->x += dx;
     delta = (s->width - is->w) / 2;
     if (delta < 0) {
@@ -573,7 +655,10 @@
 
 static void image_mode_close(EditState *s)
 {
-    ImageState *is = s->mode_data;
+    ImageState *is = image_get_state(s, 0);
+
+    if (!is)
+        return;
 
     bmp_free(s->screen, &is->disp_bmp);
     eb_free_callback(s->b, image_callback, s);
@@ -663,12 +748,16 @@
 
 static void image_rotate(EditState *e)
 {
-    ImageState *is = e->mode_data;
-    EditBuffer *b = e->b;
-    ImageBuffer *ib = b->data;
+    ImageState *is = image_get_state(e, 1);
+    ImageBuffer *ib;
     int ret, w, h, pix_fmt;
     ImageBuffer *ib1;
 
+    if (!is)
+        return;
+
+    ib = is->ibs->ib;
+
     pix_fmt = ib->pix_fmt;
     w = ib->width;
     h = ib->height;
@@ -686,8 +775,7 @@
         return;
     }
     ib1->alpha_info = ib->alpha_info;
-    set_new_image(b, ib1);
-    image_free(ib);
+    set_new_image(e->b, ib1);
     /* temporary */
     is->w = h;
     is->h = w;
@@ -697,7 +785,10 @@
 
 static void image_set_background_color(EditState *e, const char *color_str)
 {
-    ImageState *is = e->mode_data;
+    ImageState *is = image_get_state(s, 0);
+
+    if (!is)
+        return;
 
     css_get_color(&is->background_color, color_str);
     update_bmp(e);
@@ -705,12 +796,17 @@
 
 static void image_convert(EditState *e, const char *pix_fmt_str)
 {
-    EditBuffer *b = e->b;
-    ImageBuffer *ib = b->data;
+    ImageState *is = image_get_state(s, 0);
+    ImageBuffer *ib;
     int ret, new_pix_fmt, i, loss;
     ImageBuffer *ib1;
     const char *name;
 
+    if (!is)
+        return;
+
+    ib = is->ibs->ib;
+
     for (i = 0; i < PIX_FMT_NB; i++) {
         name = avcodec_get_pix_fmt_name(i);
         if (strequal(name, pix_fmt_str))
@@ -754,8 +850,7 @@
     }
     ib1->alpha_info = img_get_alpha_info(&ib1->pict, ib1->pix_fmt,
                                          ib1->width, ib1->height);
-    set_new_image(b, ib1);
-    image_free(ib);
+    set_new_image(e->b, ib1);
     /* suppress that and use callback */
     update_bmp(e);
 }
@@ -763,9 +858,15 @@
 void image_mode_line(EditState *s, buf_t *out)
 {
     EditBuffer *b = s->b;
-    ImageBuffer *ib = b->data;
+    ImageState *is = image_get_state(s, 0);
+    ImageBuffer *ib;
     char alpha_mode;
 
+    if (!is)
+        return;
+
+    ib = is->ib;
+
     basic_mode_line(s, out, '-');
 
     if (ib->alpha_info & FF_ALPHA_SEMI_TRANSP)
@@ -822,12 +923,21 @@
     CMD_DEF_END,
 };
 
+static EditBufferDataType image_data_type = {
+    "image",
+    image_buffer_load,
+    image_buffer_save,
+    image_buffer_close,
+};
+
 ModeDef image_mode = {
     .name = "image",
-    .instance_size = sizeof(ImageState),
+    .buffer_instance_size = sizeof(ImageBufferState),
+    .window_instance_size = sizeof(ImageState),
     .mode_probe = image_mode_probe,
     .mode_init = image_mode_init,
     .mode_close = image_mode_close,
+    .mode_free = image_mode_free,
     .display = image_display,
     .move_up_down = image_move_up_down,
     .move_left_right = image_move_left_right,
@@ -836,13 +946,6 @@
     .get_mode_line = image_mode_line,
 };
 
-static EditBufferDataType image_data_type = {
-    "image",
-    image_buffer_load,
-    image_buffer_save,
-    image_buffer_close,
-};
-
 static int image_init(void)
 {
     av_register_all();

Index: shell.c
===================================================================
RCS file: /sources/qemacs/qemacs/shell.c,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -b -r1.100 -r1.101
--- shell.c     26 Aug 2015 22:51:25 -0000      1.100
+++ shell.c     27 Aug 2015 15:32:11 -0000      1.101
@@ -53,7 +53,7 @@
 };
 
 typedef struct ShellState {
-    ModeDef *signature;
+    QEModeData base;
     /* buffer state */
     int pty_fd;
     int pid; /* -1 if not launched */
@@ -653,17 +653,9 @@
 #endif
 }
 
-static ShellState *shell_get_state(EditState *e, int status)
+static inline ShellState *shell_get_state(EditState *e, int status)
 {
-    ShellState *s = e->b->priv_data;
-
-    if (s && s->signature == &shell_mode)
-        return s;
-
-    if (status)
-        put_status(e, "Not a shell buffer");
-
-    return NULL;
+    return qe_get_buffer_mode_data(e->b, &shell_mode, status ? e : NULL);
 }
 
 /* CG: much cleaner way! */
@@ -685,7 +677,7 @@
     const char *p;
     int len;
 
-    if (!s || s->signature != &shell_mode)
+    if (!s || s->base.mode != &shell_mode)
         return;
 
     if (key == KEY_CTRL('o')) {
@@ -1242,7 +1234,7 @@
     unsigned char buf[16 * 1024];
     int len, i;
 
-    if (!s || s->signature != &shell_mode)
+    if (!s || s->base.mode != &shell_mode)
         return;
 
     qs = s->qe_state;
@@ -1259,6 +1251,12 @@
         s->b->flags &= ~BF_READONLY;
         s->b->last_log = 0;
 
+#if 0
+        /* XXX: tty emulation should be optional */
+        if (!emulate) {
+            eb_write(s->b, s->b->total_size, buf, len);
+        } else
+#endif
         for (i = 0; i < len; i++)
             tty_emulate(s, buf[i]);
 
@@ -1272,14 +1270,11 @@
     dpy_flush(qs->screen);
 }
 
-static void shell_close(EditBuffer *b)
+static void shell_mode_free(EditBuffer *b, void *state)
 {
-    ShellState *s = b->priv_data;
+    ShellState *s = state;
     int status;
 
-    if (!s || s->signature != &shell_mode)
-        return;
-
     eb_free_callback(b, eb_offset_callback, &s->cur_offset);
 
     if (s->pid != -1) {
@@ -1302,9 +1297,6 @@
         close(s->pty_fd);
         s->pty_fd = -1;
     }
-    qe_free(&b->priv_data);
-    if (b->close == shell_close)
-        b->close = NULL;
 }
 
 static void shell_pid_cb(void *opaque, int status)
@@ -1315,7 +1307,7 @@
     EditState *e;
     char buf[1024];
 
-    if (!s || s->signature != &shell_mode)
+    if (!s || s->base.mode != &shell_mode)
         return;
 
     b = s->b;
@@ -1374,7 +1366,7 @@
             qe_set_next_mode(e, 0, 0);
     }
     if (!(s->shell_flags & SF_INTERACTIVE)) {
-        shell_close(b);
+        qe_free_mode_data(&s->base);
     }
     edit_display(qs);
     dpy_flush(qs->screen);
@@ -1391,22 +1383,15 @@
     int rows, cols;
 
     b = b0;
-    if (b) {
-        s = b->priv_data;
-        if (s && s->signature != &shell_mode)
-            return NULL;
-        if (shell_flags & SF_COLOR)
-            eb_create_style_buffer(b, BF_STYLE2);
-    } else {
-        int bf_flags = BF_SAVELOG;
-        if (shell_flags & SF_COLOR)
-            bf_flags |= BF_STYLE2;
-        b = eb_new(bufname, bf_flags);
+    if (!b) {
+        b = eb_new(bufname, BF_SAVELOG);
         if (!b)
             return NULL;
     }
 
     eb_set_buffer_name(b, bufname); /* ensure that the name is unique */
+    if (shell_flags & SF_COLOR)
+        eb_create_style_buffer(b, BF_STYLE2);
 
     /* Select shell output buffer encoding from LANG setting */
     if (((lang = getenv("LANG")) != NULL && strstr(lang, "UTF-8")) ||
@@ -1416,17 +1401,14 @@
         eb_set_charset(b, &charset_vt100, b->eol_type);
     }
 
-    s = b->priv_data;
+    s = qe_get_buffer_mode_data(b, &shell_mode, NULL);
     if (!s) {
-        s = qe_mallocz(ShellState);
+        s = (ShellState*)qe_create_buffer_mode_data(b, &shell_mode);
         if (!s) {
             if (!b0)
                 eb_free(&b);
             return NULL;
         }
-        s->signature = &shell_mode;
-        b->priv_data = s;
-        b->close = shell_close;
         /* Track cursor with edge effect */
         eb_add_callback(b, eb_offset_callback, &s->cur_offset, 1);
     }
@@ -1493,25 +1475,19 @@
          * restart shell process in it.
          */
         b = s->b;
-        shs = b->priv_data;
-        if (strstart(b->name, "*shell*", NULL)
-        &&  shs && shs->signature == &shell_mode) {
+        shs = shell_get_state(s, 0);
+        if (shs && strstart(b->name, "*shell", NULL)) {
             if (shs->pid >= 0)
                 return;
         } else {
             /* XXX: should find the last used shell buffer */
             b = try_show_buffer(s, "*shell*");
             if (b) {
-                shs = b->priv_data;
-                if (shs) {
-                    if (shs->signature != &shell_mode) {
-                        b = NULL;
-                    } else
-                    if (shs->pid >= 0)
+                shs = qe_get_buffer_mode_data(b, &shell_mode, NULL);
+                if (shs && shs->pid >= 0)
                         return;
                 }
             }
-        }
         if (b) {
             /* restart shell in *shell* buffer */
             s->offset = b->total_size;
@@ -1573,7 +1549,6 @@
     b->data_type_name = "ssh";
     b->default_mode = &shell_mode;
     switch_to_buffer(s, b);
-    //edit_set_mode(s, &shell_mode);
 
     put_status(s, "Press C-o to toggle between shell/edit mode");
 }
@@ -1966,13 +1941,11 @@
 
 static int shell_mode_probe(ModeDef *mode, ModeProbeData *p)
 {
-    if (p->b && p->b->priv_data) {
-        ShellState *s = p->b->priv_data;
-        if (s->signature == &shell_mode) {
-            if (s->shell_flags & SF_INTERACTIVE)
+    ShellState *s = qe_get_buffer_mode_data(p->b, &shell_mode, NULL);
+
+    if (s && s->shell_flags & SF_INTERACTIVE)
                 return 100;
-        }
-    }
+
     return 0;
 }
 
@@ -2008,7 +1981,9 @@
     shell_mode.name = "shell";
     shell_mode.mode_name = NULL;
     shell_mode.mode_probe = shell_mode_probe;
+    shell_mode.buffer_instance_size = sizeof(ShellState);
     shell_mode.mode_init = shell_mode_init;
+    shell_mode.mode_free = shell_mode_free;
     shell_mode.display_hook = shell_display_hook;
     shell_mode.move_left_right = shell_move_left_right;
     shell_mode.move_word_left_right = shell_move_word_left_right;

Index: bufed.c
===================================================================
RCS file: /sources/qemacs/qemacs/bufed.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- bufed.c     26 Aug 2015 01:07:29 -0000      1.39
+++ bufed.c     27 Aug 2015 15:32:12 -0000      1.40
@@ -36,7 +36,7 @@
 };
 
 typedef struct BufedState {
-    ModeDef *signature;
+    QEModeData base;
     int flags;
     int last_index;
     EditState *cur_window;
@@ -47,31 +47,19 @@
 
 static ModeDef bufed_mode;
 
-static BufedState *bufed_get_state(EditState *s, int status)
+static inline BufedState *bufed_get_state(EditState *e, int status)
 {
-    BufedState *bs = s->b->priv_data;
-
-    if (bs && bs->signature == &bufed_mode)
-        return bs;
-
-    if (status)
-        put_status(s, "Not a bufed buffer");
-
-    return NULL;
+    return qe_get_buffer_mode_data(e->b, &bufed_mode, status ? e : NULL);
 }
 
-static void build_bufed_list(EditState *s)
+static void build_bufed_list(BufedState *bs, EditState *s)
 {
     QEmacsState *qs = s->qe_state;
     EditBuffer *b;
-    BufedState *bs;
     StringItem *item;
     int last_index = list_get_pos(s);
     int i;
 
-    if (!(bs = bufed_get_state(s, 1)))
-        return;
-
     free_strings(&bs->items);
     for (b = qs->first_buffer; b != NULL; b = b->next) {
         if (!(b->flags & BF_SYSTEM) || (bs->flags & BUFED_ALL_VISIBLE)) {
@@ -127,6 +115,7 @@
             char mode_buf[64];
             const char *mode_name;
             buf_t outbuf, *out;
+            QEModeData *md;
 
             if (b1->flags & BF_IS_LOG) {
                 mode_name = "log";
@@ -150,6 +139,10 @@
                 buf_printf(out, "%s+", b1->data_type_name);
             }
             buf_puts(out, mode_name);
+            for (md = b1->mode_data_list; md; md = md->next) {
+                if (md->mode && md->mode != b1->saved_mode)
+                    buf_printf(out, ",%s", md->mode->name);
+            }
 
             b->cur_style = style0;
             eb_printf(b, " %10d %1.0d %-8.8s %-11s ",
@@ -169,14 +162,10 @@
     b->flags |= BF_READONLY;
 }
 
-static EditBuffer *bufed_get_buffer(EditState *s)
+static EditBuffer *bufed_get_buffer(BufedState *bs, EditState *s)
 {
-    BufedState *bs;
     int index;
 
-    if (!(bs = bufed_get_state(s, 1)))
-        return NULL;
-
     index = list_get_pos(s);
     if (index < 0 || index >= bs->items.nb_items)
         return NULL;
@@ -272,7 +261,7 @@
 
     string_selection_iterate(&bs->items, list_get_pos(s),
                              bufed_kill_item, s);
-    build_bufed_list(s);
+    build_bufed_list(bs, s);
 }
 
 /* show a list of buffers */
@@ -316,7 +305,7 @@
     } else {
         bs->flags |= BUFED_ALL_VISIBLE;
     }
-    build_bufed_list(e);
+    build_bufed_list(bs, e);
 
     /* if active buffer is found, go directly on it */
     for (i = 0; i < bs->items.nb_items; i++) {
@@ -329,26 +318,34 @@
 
 static void bufed_clear_modified(EditState *s)
 {
+    BufedState *bs;
     EditBuffer *b;
 
-    b = bufed_get_buffer(s);
+    if (!(bs = bufed_get_state(s, 1)))
+        return;
+
+    b = bufed_get_buffer(bs, s);
     if (!b)
         return;
 
     b->modified = 0;
-    build_bufed_list(s);
+    build_bufed_list(bs, s);
 }
 
 static void bufed_toggle_read_only(EditState *s)
 {
+    BufedState *bs;
     EditBuffer *b;
 
-    b = bufed_get_buffer(s);
+    if (!(bs = bufed_get_state(s, 1)))
+        return;
+
+    b = bufed_get_buffer(bs, s);
     if (!b)
         return;
 
     b->flags ^= BF_READONLY;
-    build_bufed_list(s);
+    build_bufed_list(bs, s);
 }
 
 static void bufed_refresh(EditState *s, int toggle)
@@ -361,7 +358,7 @@
     if (toggle)
         bs->flags ^= BUFED_ALL_VISIBLE;
 
-    build_bufed_list(s);
+    build_bufed_list(bs, s);
 }
 
 static void bufed_display_hook(EditState *s)
@@ -376,52 +373,27 @@
 
 static int bufed_mode_probe(ModeDef *mode, ModeProbeData *p)
 {
-    if (p->b->priv_data) {
-        BufedState *bs = p->b->priv_data;
-        if (bs->signature == &bufed_mode)
+    if (qe_get_buffer_mode_data(p->b, &bufed_mode, NULL))
             return 95;
-        else
-            return 0;
-    }
+
     return 0;
 }
 
-static void bufed_close(EditBuffer *b)
+static int bufed_mode_init(EditState *s, EditBuffer *b, int flags)
 {
-    BufedState *bs = b->priv_data;
+    BufedState *bs = qe_get_buffer_mode_data(b, &bufed_mode, NULL);
 
-    if (bs && bs->signature == &bufed_mode) {
-        free_strings(&bs->items);
-    }
+    if (!bs)
+        return -1;
 
-    qe_free(&b->priv_data);
-    if (b->close == bufed_close)
-        b->close = NULL;
+    return list_mode.mode_init(s, b, flags);
 }
 
-static int bufed_mode_init(EditState *s, EditBuffer *b, int flags)
+static void bufed_mode_free(EditBuffer *b, void *state)
 {
-    BufedState *bs;
+    BufedState *bs = state;
 
-    list_mode.mode_init(s, b, flags);
-
-    if (s) {
-        if (s->b->priv_data) {
-            bs = s->b->priv_data;
-            if (bs->signature != &bufed_mode)
-                return -1;
-        } else {
-            /* XXX: should be allocated by buffer_load API */
-            bs = qe_mallocz(BufedState);
-            if (!bs)
-                return -1;
-
-            bs->signature = &bufed_mode;
-            s->b->priv_data = bs;
-            s->b->close = bufed_close;
-        }
-    }
-    return 0;
+    free_strings(&bs->items);
 }
 
 /* specific bufed commands */
@@ -466,7 +438,9 @@
     memcpy(&bufed_mode, &list_mode, sizeof(ModeDef));
     bufed_mode.name = "bufed";
     bufed_mode.mode_probe = bufed_mode_probe;
+    bufed_mode.buffer_instance_size = sizeof(BufedState);
     bufed_mode.mode_init = bufed_mode_init;
+    bufed_mode.mode_free = bufed_mode_free;
     bufed_mode.display_hook = bufed_display_hook;
 
     /* first register mode */

Index: docbook.c
===================================================================
RCS file: /sources/qemacs/qemacs/docbook.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- docbook.c   1 Jun 2014 13:54:59 -0000       1.12
+++ docbook.c   27 Aug 2015 15:32:13 -0000      1.13
@@ -34,7 +34,12 @@
 
 static int docbook_mode_init(EditState *s, EditBuffer *b, int flags)
 {
-    return gxml_mode_init(s, XML_IGNORE_CASE | XML_DOCBOOK, docbook_style);
+    if (flags & MODEF_NEWINSTANCE) {
+        /* Implement mode inheritance manually */
+        qe_create_buffer_mode_data(b, &html_mode);
+        return gxml_mode_init(b, XML_IGNORE_CASE | XML_DOCBOOK, docbook_style);
+    }
+    return 0;
 }
 
 static ModeDef docbook_mode;
@@ -44,6 +49,7 @@
     /* inherit from html mode */
     memcpy(&docbook_mode, &html_mode, sizeof(ModeDef));
     docbook_mode.name = "docbook";
+    docbook_mode.buffer_instance_size = sizeof(QEModeData);
     docbook_mode.extensions = NULL;
     docbook_mode.mode_probe = docbook_mode_probe;
     docbook_mode.mode_init = docbook_mode_init;

Index: qe.c
===================================================================
RCS file: /sources/qemacs/qemacs/qe.c,v
retrieving revision 1.209
retrieving revision 1.210
diff -u -b -r1.209 -r1.210
--- qe.c        26 Aug 2015 22:51:24 -0000      1.209
+++ qe.c        27 Aug 2015 15:32:14 -0000      1.210
@@ -1846,7 +1846,7 @@
     if (b->filename[0] == '\0')
         return 0;
 
-    if (b->data_type == &raw_data_type) {
+    if (!f1 && b->data_type == &raw_data_type) {
         struct stat st;
 
         if (stat(b->filename, &st) < 0 || !S_ISREG(st.st_mode))
@@ -1859,6 +1859,11 @@
     } else {
         f = f1;
     }
+    /* XXX: the log buffer is inappropriate if the file was modified on
+     * disk. If this is a reload operation, should create a log for
+     * clearing the buffer and another one for loading it. So the
+     * operation can be undone.
+     */
     saved = b->save_log;
     b->save_log = 0;
     if (b->data_type->buffer_load)
@@ -1884,13 +1889,104 @@
     }
 }
 
-void edit_set_mode(EditState *s, ModeDef *m)
+QEModeData *qe_create_buffer_mode_data(EditBuffer *b, ModeDef *m)
 {
-    int data_count;
-    EditState *e;
-    EditBuffer *b;
+    QEModeData *md = NULL;
+    int size = m->buffer_instance_size - sizeof(QEModeData);
 
-    b = s->b;
+    if (size >= 0) {
+        md = qe_mallocz_hack(QEModeData, size);
+        if (md) {
+            md->mode = m;
+            md->b = b;
+            md->next = b->mode_data_list;
+            b->mode_data_list = md;
+        }
+    }
+    return md;
+}
+
+void *qe_get_buffer_mode_data(EditBuffer *b, ModeDef *m, EditState *e)
+{
+    if (b) {
+        QEModeData *md;
+        for (md = b->mode_data_list; md; md = md->next) {
+            if (md->mode == m)
+                return md;
+        }
+    }
+    if (e)
+        put_status(e, "Not a %s buffer", m->name);
+
+    return NULL;
+}
+
+QEModeData *qe_create_window_mode_data(EditState *s, ModeDef *m)
+{
+    QEModeData *md = NULL;
+    int size = m->window_instance_size - sizeof(QEModeData);
+
+    if (!s->mode_data && size >= 0) {
+        md = qe_mallocz_hack(QEModeData, size);
+        if (md) {
+            md->mode = m;
+            md->s = s;
+            s->mode_data = md;
+        }
+    }
+    return md;
+}
+
+void *qe_get_window_mode_data(EditState *e, ModeDef *m, int status)
+{
+    if (e) {
+        QEModeData *md = e->mode_data;
+        if (md && md->mode == m)
+            return md;
+    }
+    if (status)
+        put_status(e, "Not a %s buffer", m->name);
+
+    return NULL;
+}
+
+int qe_free_mode_data(QEModeData *md)
+{
+    int rc = -1;
+
+    if (!md)
+        return 0;
+
+    if (check_buffer(&md->b)) {
+        EditBuffer *b = md->b;
+        QEModeData **mdp;
+        for (mdp = &b->mode_data_list; *mdp; mdp = &(*mdp)->next) {
+            if (*mdp == md) {
+                /* unlink before calling destructor */
+                *mdp = md->next;
+                if (md->mode->mode_free)
+                    md->mode->mode_free(b, md);
+                rc = 0;
+                break;
+            }
+        }
+    }
+    if (check_window(&md->s)) {
+        if (md->s->mode_data == md) {
+            md->s->mode_data = NULL;
+            rc = 0;
+        }
+    }        
+    qe_free(&md);
+    return rc;
+}
+
+int edit_set_mode(EditState *s, ModeDef *m)
+{
+    int mode_flags = 0;
+    EditBuffer *b = s->b;
+    const char *errstr = NULL;
+    int rc = 0;
 
     /* if a mode is already defined, try to close it */
     if (s->mode) {
@@ -1899,16 +1995,21 @@
         if (s->mode->mode_close)
             s->mode->mode_close(s);
         generic_mode_close(s);
-        qe_free(&s->mode_data);
-        s->mode = NULL;
+        qe_free_mode_data(s->mode_data);
+        s->mode = NULL;  /* XXX: should instead use fundamental_mode */
         set_colorize_func(s, NULL);
 
+        /* XXX: this code makes no sense, if must be reworked! */
+#if 0
+        int data_count;
+        EditState *e;
+
         /* try to remove the raw or mode specific data if it is no
            longer used. */
         data_count = 0;
         for (e = s->qe_state->first_window; e != NULL; e = e->next_window) {
             if (e != s && e->b == b) {
-                if (e->mode->data_type != &raw_data_type)
+                if (e->mode && e->mode->data_type != &raw_data_type)
                     data_count++;
             }
         }
@@ -1917,6 +2018,8 @@
         if (data_count == 0 && !b->modified) {
             /* close mode specific buffer representation because it is
                always redundant if it was not modified */
+            /* XXX: move this to reset buffer data: eb_free or changing
+             * data_type */
             if (b->data_type != &raw_data_type) {
                 b->data_type->buffer_close(b);
                 b->data_data = NULL;
@@ -1925,36 +2028,46 @@
                 b->modified = 0;
             }
         }
+#endif
     }
 
     /* if a new mode is wanted, open it */
     if (m) {
         s->mode_data = NULL;
-        if (m->instance_size > 0) {
-            s->mode_data = qe_mallocz_array(u8, m->instance_size);
+        if (m->buffer_instance_size > 0) {
+            if (!qe_get_buffer_mode_data(b, m, NULL)) {
+                if (qe_create_buffer_mode_data(b, m)) {
+                    mode_flags = MODEF_NEWINSTANCE;
+                } else {
+                    errstr = "Cannot allocate buffer mode data";
+                }
+            }
+        }
+        if (m->window_instance_size > 0) {
+            if (!qe_create_window_mode_data(s, m)) {
             /* safe fall back: use text mode */
-            if (!s->mode_data)
-                m = &text_mode;
+                errstr = "Cannot allocate window mode data";
+            }
         }
         if (m->data_type != &raw_data_type) {
             /* if a non raw data type is requested, we see if we can use it */
             if (b->data_type == &raw_data_type) {
                 /* non raw data type: we must call a mode specific
                    load method */
+                s->mode = m;
                 b->data_type = m->data_type;
                 b->data_type_name = m->data_type->name;
                 if (reload_buffer(s, b) < 0) {
-                    /* error: reset to text mode */
-                    m = &text_mode;
                     b->data_type = &raw_data_type;
                     b->data_type_name = NULL;
+                    errstr = "Cannot reload buffer";
                 }
             } else
             if (b->data_type != m->data_type) {
                 /* non raw data type requested, but the the buffer has
                    a different type: we cannot switch mode, so we fall
                    back to text */
-                m = &text_mode;
+                errstr = "incompatible data type";
             } else {
                 /* same data type: nothing more to do */
             }
@@ -1963,11 +2076,17 @@
             if (b->total_size == 0 && !b->modified)
                 reload_buffer(s, b);
         }
+        if (errstr) {
+            put_status(s, "Cannot set mode %s: %s", m->name, errstr);
+            m = &text_mode;
+            rc = -1;
+        }
+
         s->mode = m;
 
         /* init mode */
         generic_mode_init(s);
-        m->mode_init(s, s->b, MODEF_VIEW);
+        m->mode_init(s, s->b, MODEF_VIEW | mode_flags);
         if (m->colorize_func)
             set_colorize_func(s, m->colorize_func);
         /* modify offset_top so that its value is correct */
@@ -1976,6 +2095,7 @@
         /* keep saved data in sync with last mode used for buffer */
         generic_save_window_data(s);
     }
+    return rc;
 }
 
 void do_set_mode(EditState *s, const char *name)
@@ -5071,9 +5191,10 @@
     }
 }
 
-/* close the edit window. If it is active, find another active
-   window. If the buffer is only referenced by this window, then save
-   in the buffer all the window state so that it can be recovered. */
+/* Close the edit window.
+ * Save the window state to the buffer for later retrieval.
+ * If it is active, find another window to activate.
+ */
 void edit_close(EditState **sp)
 {
     if (*sp) {
@@ -5082,7 +5203,7 @@
         /* save current state for later window reattachment */
         switch_to_buffer(s, NULL);
         edit_detach(s);
-        qe_free(&s->mode_data);
+        qe_free_mode_data(s->mode_data);
         qe_free(&s->prompt);
         qe_free(&s->line_shadow);
         qe_free(sp);
@@ -5713,6 +5834,7 @@
 
     e_new = edit_new(b, 0, 0, width, qs->height - qs->status_height,
                      flags | WF_POPLEFT | WF_RSEPARATOR);
+    e_new->wrap = WRAP_TRUNCATE;
     do_refresh(e_new);
     return e_new;
 }
@@ -6164,10 +6286,15 @@
             f = NULL;
         }
 
-        /* Attach buffer to window, will set default_mode
-         * XXX: this will also load the file, incorrect for non raw modes
-         */
         b->default_mode = selected_mode;
+        /* attaching the buffer to the window will set the default_mode
+         * which in turn will load the data.
+         * XXX: This is an ugly side effect, ineffective for
+         * asynchronous shell buffers.
+         * XXX: should instead instantiate the mode on the buffer and
+         * test the resulting data_mode, loading the file if raw_mode
+         * selected.
+         */
         switch_to_buffer(s, b);
         if (access(b->filename, W_OK)) {
             b->flags |= BF_READONLY;

Index: video.c
===================================================================
RCS file: /sources/qemacs/qemacs/video.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -b -r1.20 -r1.21
--- video.c     1 Jun 2014 13:55:00 -0000       1.20
+++ video.c     27 Aug 2015 15:32:24 -0000      1.21
@@ -51,6 +51,7 @@
 } VideoPicture;
 
 typedef struct VideoState {
+    QEModeData base;
     EditState *edit_state;
     pthread_t parse_tid;
     pthread_t audio_tid;
@@ -207,14 +208,22 @@
     return ret;
 }
 
+static inline VideoState *video_get_state(EditState *e, int status)
+{
+    return qe_get_window_mode_data(e, &video_mode, status);
+}
+
 /* called to display each frame */
 static void video_refresh_timer(void *opaque)
 {
     EditState *s = opaque;
     QEmacsState *qs = &qe_state;
-    VideoState *is = s->mode_data;
+    VideoState *is;
     VideoPicture *vp;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
     if (is->video_st) {
         if (is->pictq_size == 0) {
             /* if no picture, need to wait */
@@ -263,11 +272,14 @@
 
 static void video_image_display(EditState *s)
 {
-    VideoState *is = s->mode_data;
+    VideoState *is;
     VideoPicture *vp;
     float aspect_ratio;
     int width, height, x, y;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
     vp = &is->pictq[is->pictq_rindex];
     if (vp->bmp) {
         /* XXX: use variable in the frame */
@@ -301,9 +313,12 @@
 
 static void video_audio_display(EditState *s)
 {
-    VideoState *is = s->mode_data;
+    VideoState *is;
     int i, x, y1, y, h, ys;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
     fill_rectangle(s->screen,
                    s->xleft, s->ytop, s->width, s->height,
                    QERGB(0x00, 0x00, 0x00));
@@ -333,7 +348,10 @@
 /* display the current picture, if any */
 static void video_display(EditState *s)
 {
-    VideoState *is = s->mode_data;
+    VideoState *is;
+
+    if (!(is = video_get_state(s, 1)))
+        return;
 
     if (s->display_invalid) {
         if (is->video_st)
@@ -583,16 +601,20 @@
 /* open a given stream. Return 0 if OK */
 static int stream_open(EditState *s, int stream_index)
 {
-    VideoState *is = s->mode_data;
-    AVFormatContext *ic = is->ic;
+    VideoState *is;
+    AVFormatContext *ic;
     AVCodecContext *enc;
     AVCodec *codec;
     AVStream *st;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
+    ic = is->ic;
     if (stream_index < 0 || stream_index >= ic->nb_streams)
         return -1;
-    enc = &ic->streams[stream_index]->codec;
 
+    enc = &ic->streams[stream_index]->codec;
 
     /* prepare audio output */
     if (enc->codec_type == CODEC_TYPE_AUDIO) {
@@ -636,10 +658,14 @@
 
 static void stream_close(EditState *s, int stream_index)
 {
-    VideoState *is = s->mode_data;
-    AVFormatContext *ic = is->ic;
+    VideoState *is;
+    AVFormatContext *ic;
     AVCodecContext *enc;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
+    ic = is->ic;
     enc = &ic->streams[stream_index]->codec;
 
     switch (enc->codec_type) {
@@ -690,11 +716,14 @@
 static void *decode_thread(void *arg)
 {
     EditState *s = arg;
-    VideoState *is = s->mode_data;
+    VideoState *is;
     AVFormatContext *ic;
     int err, i, ret, video_index, audio_index;
     AVPacket pkt1, *pkt = &pkt1;
 
+    if (!(is = video_get_state(s, 1)))
+        return NULL;
+
     video_index = -1;
     audio_index = -1;
     is->video_stream = -1;
@@ -785,18 +814,25 @@
 /* pause or resume the video */
 static void video_pause(EditState *s)
 {
-    VideoState *is = s->mode_data;
+    VideoState *is;
+
+    if (!(is = video_get_state(s, 1)))
+        return;
+
     is->paused = !is->paused;
 }
 
 static int video_mode_init(EditState *s, EditBuffer *b, int flags)
 {
     if (s) {
-        VideoState *is = s->mode_data;
+        VideoState *is = qe_get_buffer_mode_data(b, &video_mode, NULL);
         QEmacsState *qs = s->qe_state;
         int err, video_playing;
         EditState *e;
 
+        if (!is)
+            return -1;
+
         /* XXX: avoid annoying Overwrite in mode line */
         s->insert = 1;
 
@@ -811,10 +847,11 @@
         /* if there is already a window with this video playing, then we
            stop this new instance (C-x 2 case) */
         video_playing = 0;
+        /* need window based mode data for this */
         for (e = qs->first_window; e != NULL; e = e->next_window) {
             if (e->mode == s->mode && e != s && e->b == s->b) {
-                VideoState *is1 = e->mode_data;
-                if (!is1->paused)
+                VideoState *is1 = qe_get_window_mode_data(e, &video_mode, 0);
+                if (is1 && !is1->paused)
                     video_playing = 1;
             }
         }
@@ -832,10 +869,13 @@
 
 static void video_mode_close(EditState *s)
 {
-    VideoState *is = s->mode_data;
+    VideoState *is;
     VideoPicture *vp;
     int i;
 
+    if (!(is = video_get_state(s, 1)))
+        return;
+
     /* XXX: use a special url_shutdown call to abort parse cleanly */
     is->abort_request = 1;
     pthread_join(is->parse_tid, NULL);
@@ -863,13 +903,16 @@
 static void video_mode_line(EditState *s, buf_t *out)
 {
     const char *name;
-    VideoState *is = s->mode_data;
+    VideoState *is;
     AVCodec *codec;
     AVCodecContext *dec;
     char buf1[32];
 
     basic_mode_line(s, out, '-');
 
+    if (!(is = video_get_state(s, 0)))
+        return;
+
     if (is->paused)
         buf_printf(out, "[paused]--");
 
@@ -901,16 +944,22 @@
 
 static void av_cycle_stream(EditState *s, int codec_type)
 {
-    VideoState *is = s->mode_data;
-    AVFormatContext *ic = is->ic;
+    VideoState *is;
+    AVFormatContext *ic;
     int start_index, stream_index;
     AVStream *st;
     char buf[32];
 
+    if (!(is = video_get_state(s, 0)))
+        return;
+
+    ic = is->ic;
+
     if (codec_type == CODEC_TYPE_VIDEO)
         start_index = is->video_stream;
     else
         start_index = is->audio_stream;
+
     if (start_index < 0) {
         put_status(s, "No %s stream to cycle",
                    (codec_type == CODEC_TYPE_VIDEO) ? "video" : "audio");
@@ -950,7 +999,7 @@
 
 ModeDef video_mode = {
     .name = "av",
-    .instance_size = sizeof(VideoState),
+    .window_instance_size = sizeof(VideoState),
     .mode_probe = video_mode_probe,
     .mode_init = video_mode_init,
     .mode_close = video_mode_close,

Index: buffer.c
===================================================================
RCS file: /sources/qemacs/qemacs/buffer.c,v
retrieving revision 1.92
retrieving revision 1.93
diff -u -b -r1.92 -r1.93
--- buffer.c    26 Aug 2015 00:53:24 -0000      1.92
+++ buffer.c    27 Aug 2015 15:32:27 -0000      1.93
@@ -782,9 +782,15 @@
         QEmacsState *qs = &qe_state;
         EditBuffer **pb;
 
-        /* call user defined close */
-        if (b->close)
-            b->close(b);
+        /* free b->mode_data_list by calling destructors */
+        while (b->mode_data_list) {
+            QEModeData *md = b->mode_data_list;
+            b->mode_data_list = md->next;
+            md->next = NULL;
+            if (md->mode && md->mode->mode_free)
+                md->mode->mode_free(b, md);
+            qe_free(&md);
+        }
 
         /* free each callback */
         while (b->first_callback) {
@@ -811,7 +817,6 @@
         eb_free_style_buffer(b);
 
        qe_free(&b->saved_data);
-       qe_free(&b->priv_data);
         qe_free(bp);
     }
 }

Index: html.c
===================================================================
RCS file: /sources/qemacs/qemacs/html.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -b -r1.34 -r1.35
--- html.c      1 Jun 2014 13:54:59 -0000       1.34
+++ html.c      27 Aug 2015 15:32:28 -0000      1.35
@@ -29,6 +29,7 @@
 
 /* mode state */
 typedef struct HTMLState {
+    QEModeData base;
     /* default style sheet */
     CSSStyleSheet *default_style_sheet;
     CSSContext *css_ctx;
@@ -81,11 +82,19 @@
     return 0;
 }
 
+static inline HTMLState *html_get_state(EditState *e, int status)
+{
+    return qe_get_buffer_mode_data(e->b, &html_mode, status ? e : NULL);
+}
+
 static void recompute_offset(EditState *s)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     RecomputeOffsetData data;
 
+    if (!(hs = html_get_state(s, 0)))
+        return;
+
     data.ctx = hs->css_ctx;
     data.wanted_offset = s->offset;
     data.closest_offset = 0;
@@ -138,13 +147,16 @@
 
 static void html_display(EditState *s)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     CSSRect cursor_pos;
     DirType dirc;
     int n, cursor_found, d, ret, sel_start, sel_end;
     CSSRect rect;
     EditBuffer *b;
 
+    if (!(hs = html_get_state(s, 0)))
+        return;
+
     /* XXX: should be generic ? */
     if (hs->last_width != s->width) {
         hs->last_width = s->width;
@@ -379,10 +391,13 @@
 
 static void html_scroll_up_down(EditState *s, int dir)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     ScrollContext m1, *m = &m1;
     int h;
 
+    if (!(hs = html_get_state(s, 1)))
+        return;
+
     if (!hs->up_to_date)
         return;
 
@@ -491,11 +506,14 @@
 
 static void html_move_up_down1(EditState *s, int dir, int xtarget)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     MoveContext m1, *m = &m1;
     CSSRect cursor_pos;
     int dirc, offset;
 
+    if (!(hs = html_get_state(s, 1)))
+        return;
+
     /* get the cursor position in the current chunk */
     if (!css_get_cursor_pos(hs->css_ctx, hs->top_box, NULL, NULL, NULL,
                             &cursor_pos, &dirc, s->offset))
@@ -538,7 +556,10 @@
 
 static void html_move_up_down(EditState *s, int dir)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
+
+    if (!(hs = html_get_state(s, 1)))
+        return;
 
     if (!hs->up_to_date)
         return;
@@ -586,12 +607,15 @@
 /* go to left or right in visual order */
 static void html_move_left_right_visual(EditState *s, int dir)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     LeftRightMoveContext m1, *m = &m1;
     CSSRect cursor_pos;
     int dirc, offset, x0;
     CSSBox *box;
 
+    if (!(hs = html_get_state(s, 1)))
+        return;
+
     if (!hs->up_to_date)
         return;
 
@@ -635,12 +659,15 @@
 
 static void html_move_bol_eol(EditState *s, int dir)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     LeftRightMoveContext m1, *m = &m1;
     CSSRect cursor_pos;
     int dirc, offset, x0, xtarget;
     CSSBox *box;
 
+    if (!(hs = html_get_state(s, 1)))
+        return;
+
     if (!hs->up_to_date)
         return;
 
@@ -726,10 +753,13 @@
 
 static void html_mouse_goto(EditState *s, int x, int y)
 {
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs;
     MouseGotoContext m1, *m = &m1;
     int offset;
 
+    if (!(hs = html_get_state(s, 1)))
+        return;
+
     if (!hs->up_to_date)
         return;
 
@@ -756,8 +786,9 @@
                           __unused__ int offset,
                           __unused__ int size)
 {
-    EditState *s = opaque;
-    HTMLState *hs = s->mode_data;
+    HTMLState *hs = opaque;
+
+    if (hs)
     hs->up_to_date = 0;
 }
 
@@ -775,36 +806,49 @@
 
 /* graphical XML/CSS mode init. is_html is TRUE to tell that specific HTML
    quirks are needed in the parser. */
-int gxml_mode_init(EditState *s,
-                   int flags, const char *default_stylesheet)
+int gxml_mode_init(EditBuffer *b, int flags, const char *default_stylesheet)
 {
-    if (s) {
-        HTMLState *hs = s->mode_data;
+    HTMLState *hs = qe_get_buffer_mode_data(b, &html_mode, NULL);
+
+    if (!hs)
+        return -1;
 
         /* XXX: unregister callbacks for s->offset and s->top_offset ? */
 
-        eb_add_callback(s->b, html_callback, s, 0);
+    eb_add_callback(b, html_callback, hs, 0);
         hs->parse_flags = flags;
-
         load_default_style_sheet(hs, default_stylesheet, flags);
-
         hs->up_to_date = 0;
-    }
+
     return 0;
 }
 
+/* XXX: should keep parsed data for buffer lifetime? */
 static int html_mode_init(EditState *s, EditBuffer *b, int flags)
 {
-    return gxml_mode_init(s, XML_HTML | XML_HTML_SYNTAX | XML_IGNORE_CASE,
+    HTMLState *hs = qe_get_buffer_mode_data(b, &html_mode, NULL);
+
+    if (flags & MODEF_NEWINSTANCE) {
+        if (!hs)
+            return -1;
+        return gxml_mode_init(b, XML_HTML | XML_HTML_SYNTAX | XML_IGNORE_CASE,
                           html_style);
+    }
+    return 0;
 }
 
 static void html_mode_close(EditState *s)
 {
-    HTMLState *hs = s->mode_data;
-    eb_free_callback(s->b, html_callback, s);
+    s->busy = 0; /* make it a buffer flag? */
+}
+
+static void html_mode_free(EditBuffer *b, void *state)
+{
+    HTMLState *hs = state;
 
-    s->busy = 0;
+    eb_free_callback(b, html_callback, hs);
+
+    //s->busy = 0; /* make it a buffer flag? */
     css_delete_box(&hs->top_box);
     css_delete_document(&hs->css_ctx);
     css_free_style_sheet(&hs->default_style_sheet);
@@ -872,10 +916,11 @@
 
 ModeDef html_mode = {
     .name = "html",
-    .instance_size = sizeof(HTMLState),
+    .buffer_instance_size = sizeof(HTMLState),
     .mode_probe = html_mode_probe,
     .mode_init = html_mode_init,
     .mode_close = html_mode_close,
+    .mode_free = html_mode_free,
     .display = html_display,
     .move_left_right = html_move_left_right_visual,
     .move_up_down = html_move_up_down,

Index: qe.h
===================================================================
RCS file: /sources/qemacs/qemacs/qe.h,v
retrieving revision 1.206
retrieving revision 1.207
diff -u -b -r1.206 -r1.207
--- qe.h        26 Aug 2015 22:51:24 -0000      1.206
+++ qe.h        27 Aug 2015 15:32:28 -0000      1.207
@@ -133,6 +133,7 @@
 typedef struct QEmacsState QEmacsState;
 typedef struct DisplayState DisplayState;
 typedef struct ModeProbeData ModeProbeData;
+typedef struct QEModeData QEModeData;
 typedef struct ModeDef ModeDef;
 typedef struct QETimer QETimer;
 typedef struct QEColorizeContext QEColorizeContext;
@@ -883,8 +884,6 @@
     const char *data_type_name;
     EditBufferDataType *data_type;
     void *data_data;    /* associated buffer data, used if data_type != 
raw_data */
-    void *priv_data;    /* buffer polling & private data */
-    void (*close)(EditBuffer *);    /* called when deleting the buffer */
 
     /* buffer syntax or major mode */
     ModeDef *syntax_mode;
@@ -934,6 +933,9 @@
     ModeDef *saved_mode;
     OWNED u8 *saved_data; /* SAVED_DATA_SIZE bytes */
 
+    /* list of mode data associated with buffer */
+    OWNED QEModeData *mode_data_list;
+
     /* default mode stuff when buffer is detached from window */
     int offset;
 
@@ -1179,7 +1181,7 @@
 
     /* mode specific info */
     ModeDef *mode;
-    OWNED void *mode_data; /* mode private window based data */
+    OWNED QEModeData *mode_data; /* mode private window based data */
 
     /* state before line n, one short per line */
     /* XXX: move this to buffer based mode_data */
@@ -1249,6 +1251,14 @@
     EditBuffer *b;
 };
 
+struct QEModeData {
+    QEModeData *next;
+    ModeDef *mode;
+    EditState *s;
+    EditBuffer *b;
+    /* Other mode specific data follows */
+};
+
 struct ModeDef {
     const char *name;
     const char *mode_name;
@@ -1264,12 +1274,15 @@
 #define MODEF_MAJOR      0x04
 #define MODEF_DATATYPE   0x10
 #define MODEF_SHELLPROC  0x20
-    int instance_size; /* size of malloced instance */
+#define MODEF_NEWINSTANCE  0x100
+    int buffer_instance_size;   /* size of malloced buffer state  */
+    int window_instance_size;   /* size of malloced window state */
 
     /* return the percentage of confidence */
     int (*mode_probe)(ModeDef *m, ModeProbeData *pd);
     int (*mode_init)(EditState *s, EditBuffer *b, int flags);
     void (*mode_close)(EditState *s);
+    void (*mode_free)(EditBuffer *b, void *state);
 
     /* low level display functions (must be NULL to use text related
        functions)*/
@@ -1321,6 +1334,12 @@
 #define TTY_GET_FG(color)  (((color) >> 4) & 15)
 #define TTY_GET_BG(color)  (((color) >> 0) & 15)
 
+QEModeData *qe_create_buffer_mode_data(EditBuffer *b, ModeDef *m);
+void *qe_get_buffer_mode_data(EditBuffer *b, ModeDef *m, EditState *e);
+QEModeData *qe_create_window_mode_data(EditState *s, ModeDef *m);
+void *qe_get_window_mode_data(EditState *e, ModeDef *m, int status);
+int qe_free_mode_data(QEModeData *md);
+
 /* from tty.c */
 extern unsigned int const *tty_bg_colors;
 extern int tty_bg_colors_count;
@@ -1788,7 +1807,7 @@
 void edit_display(QEmacsState *qs);
 void edit_invalidate(EditState *s);
 void display_mode_line(EditState *s);
-void edit_set_mode(EditState *s, ModeDef *m);
+int edit_set_mode(EditState *s, ModeDef *m);
 void qe_set_next_mode(EditState *s, int dir, int status);
 void do_set_next_mode(EditState *s, int dir);
 
@@ -2029,8 +2048,8 @@
 
 extern ModeDef html_mode;
 
-int gxml_mode_init(EditState *s,
-                   int is_html, const char *default_stylesheet);
+/* flags from libqhtml/css.h */
+int gxml_mode_init(EditBuffer *b, int flags, const char *default_stylesheet);
 
 /* image.c */
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]