Mercurial > hg > forks > geeqie
changeset 2745:86dad5529aed
Merge with upstream changes.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 13 Apr 2018 19:06:23 +0300 |
parents | 28978fd4c263 (current diff) 0b612372e82c (diff) |
children | 194f2e0719ba |
files | src/Makefile.am src/editors.c src/filefilter.c src/image-load.c |
diffstat | 26 files changed, 934 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/docbook/GuideOptionsWindow.xml Sun Mar 04 19:01:45 2018 +0200 +++ b/doc/docbook/GuideOptionsWindow.xml Fri Apr 13 19:06:23 2018 +0300 @@ -69,6 +69,21 @@ </listitem> </varlistentry> </variablelist> + <variablelist> + <varlistentry> + <term> + <guilabel>Show window IDs</guilabel> + </term> + <listitem> + <para> + Show the window ID in the titlebar of each window. When multiple Geeqie windows are opened, this option shows a unique identifier for each window. It may be used in conjunction with the command line option: + <link linkend="Remotecommands"> + <programlisting>--remote --id:<ID></programlisting> + </link> + </para> + </listitem> + </varlistentry> + </variablelist> </section> <section id="Size"> <title>Size</title>
--- a/doc/docbook/GuideReferenceCommandLine.xml Sun Mar 04 19:01:45 2018 +0200 +++ b/doc/docbook/GuideReferenceCommandLine.xml Fri Apr 13 19:06:23 2018 +0300 @@ -247,6 +247,26 @@ <entry>Bring the geeqie window to the top</entry> </row> <row> + <entry /> + <entry>--id:<ID></entry> + <entry> + Window ID for following commands + <footnote id='ref3'> + <para>The ID is shown in the titlebar of the window. If multiple windows are open, it can be used to direct commands to a particular window e.g. --remote --id:main --tell</para> + </footnote> + </entry> + </row> + <row> + <entry /> + <entry>--new-window</entry> + <entry>Open new window</entry> + </row> + <row> + <entry /> + <entry>--close-window</entry> + <entry>Close window</entry> + </row> + <row> <entry>-ct:clear|clean</entry> <entry>--cache-thumbs:clear|clean</entry> <entry>clear or clean thumbnail cache</entry>
--- a/doc/docbook/GuideReferenceSupportedFormats.xml Sun Mar 04 19:01:45 2018 +0200 +++ b/doc/docbook/GuideReferenceSupportedFormats.xml Fri Apr 13 19:06:23 2018 +0300 @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <section id="GuideReferenceSupportedFormats"> <title id="titleGuideReferenceSupportedFormats">Supported File Formats</title> - <para>3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.</para> + <para>3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DDS, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.</para> <para> Refer to <link linkend="GuideReferencePixbufLoaders" endterm="titleGuideReferencePixbufLoaders" />
--- a/geeqie.1 Sun Mar 04 19:01:45 2018 +0200 +++ b/geeqie.1 Fri Apr 13 19:06:23 2018 +0300 @@ -188,6 +188,18 @@ Bring the Geeqie window to the top. .br .B +.IP \-\-id:<ID> +Window ID for following commands. +.br +.B +.IP \-\-new-window +Open new window. +.br +.B +.IP \-\-close-window +Close window. +.br +.B .IP \-ct:clear|clean,\-\-cache-thumbs:clear|clean Clear or clean thumbnail cache. .br
--- a/src/Makefile.am Sun Mar 04 19:01:45 2018 +0200 +++ b/src/Makefile.am Fri Apr 13 19:06:23 2018 +0300 @@ -181,6 +181,8 @@ image_load_tiff.h\ image_load_bpg.c\ image_load_bpg.h\ + image_load_dds.c\ + image_load_dds.h\ image_load_ffmpegthumbnailer.c\ image_load_ffmpegthumbnailer.h\ image-overlay.c \
--- a/src/collect-table.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/collect-table.c Fri Apr 13 19:06:23 2018 +0300 @@ -401,7 +401,7 @@ collection_table_update_status(ct); } -static void collection_table_select(CollectTable *ct, CollectInfo *info) +void collection_table_select(CollectTable *ct, CollectInfo *info) { ct->prev_selection = info; @@ -857,6 +857,26 @@ collection_dialog_append(NULL, ct->cd); } +static void collection_table_popup_goto_original_cb(GtkWidget *widget, gpointer data) +{ + CollectTable *ct = data; + GList *list; + LayoutWindow *lw = NULL; + FileData *fd; + + if (!layout_valid(&lw)) return; + list = collection_table_selection_get_list(ct); + if (list) + { + fd = list->data; + if (fd) + { + layout_set_fd(lw, fd); + } + } + g_list_free(list); +} + static void collection_table_popup_find_dupes_cb(GtkWidget *widget, gpointer data) { CollectTable *ct = data; @@ -914,6 +934,8 @@ G_CALLBACK(collection_table_popup_view_cb), ct); menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, over_icon, G_CALLBACK(collection_table_popup_view_new_cb), ct); + menu_item_add_stock(menu, _("Go to original"), GTK_STOCK_FIND, + G_CALLBACK(collection_table_popup_goto_original_cb), ct); menu_item_add_divider(menu); menu_item_add_stock_sensitive(menu, _("Rem_ove"), GTK_STOCK_REMOVE, over_icon, G_CALLBACK(collection_table_popup_remove_cb), ct); @@ -986,7 +1008,7 @@ *------------------------------------------------------------------- */ -static void collection_table_set_focus(CollectTable *ct, CollectInfo *info) +void collection_table_set_focus(CollectTable *ct, CollectInfo *info) { GtkTreeIter iter; gint row, col;
--- a/src/collect-table.h Sun Mar 04 19:01:45 2018 +0200 +++ b/src/collect-table.h Fri Apr 13 19:06:23 2018 +0300 @@ -41,6 +41,7 @@ CollectInfo *collection_table_get_focus_info(CollectTable *ct); GList *collection_table_selection_get_list(CollectTable *ct); - +void collection_table_set_focus(CollectTable *ct, CollectInfo *info); +void collection_table_select(CollectTable *ct, CollectInfo *info); #endif /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/editors.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/editors.c Fri Apr 13 19:06:23 2018 +0300 @@ -111,7 +111,7 @@ {"image/*", "*"}, {"image/bmp", ".bmp"}, {"image/gif", ".gif"}, - {"image/jpeg", ".jpeg;.jpg"}, + {"image/jpeg", ".jpeg;.jpg;.mpo"}, {"image/jpg", ".jpg;.jpeg"}, {"image/bpg", ".bpg"}, {"image/pcx", ".pcx"}, @@ -119,19 +119,25 @@ {"image/svg", ".svg"}, {"image/svg+xml", ".svg"}, {"image/svg+xml-compressed", ".svg"}, - {"image/tiff", ".tiff;.tif"}, + {"image/tiff", ".tiff;.tif;.mef"}, + {"image/vnd-ms.dds", ".dds"}, + {"image/x-adobe-dng", ".dng"}, {"image/x-bmp", ".bmp"}, {"image/x-canon-crw", ".crw"}, {"image/x-canon-cr2", ".cr2"}, {"image/x-cr2", ".cr2"}, - {"image/x-dcraw", "%raw"}, + {"image/x-dcraw", "%raw;.mos"}, {"image/x-epson-erf", "%erf"}, {"image/x-ico", ".ico"}, + {"image/x-kodak-kdc", ".kdc"}, {"image/x-mrw", ".mrw"}, {"image/x-minolta-mrw", ".mrw"}, {"image/x-MS-bmp", ".bmp"}, {"image/x-nef", ".nef"}, {"image/x-nikon-nef", ".nef"}, + {"image/x-panasonic-raw", ".raw"}, + {"image/x-panasonic-rw2", ".rw2"}, + {"image/x-pentax-pef", ".pef"}, {"image/x-orf", ".orf"}, {"image/x-olympus-orf", ".orf"}, {"image/x-pcx", ".pcx"}, @@ -145,11 +151,15 @@ {"image/x-raf", ".raf"}, {"image/x-fuji-raf", ".raf"}, {"image/x-sgi", ".sgi"}, + {"image/x-sony-arw", ".arw"}, + {"image/x-sony-sr2", ".sr2"}, + {"image/x-sony-srf", ".srf"}, {"image/x-tga", ".tga"}, {"image/x-xbitmap", ".xbm"}, {"image/x-xcf", ".xcf"}, {"image/x-xpixmap", ".xpm"}, {"image/x-x3f", ".x3f"}, + {"application/x-navi-animation", ".ani"}, {"application/x-ptoptimizer-script", ".pto"}, {NULL, NULL}}; @@ -544,7 +554,7 @@ NULL, FALSE, NULL, ed); buf = g_strdup_printf(_("Output of %s"), text); - generic_dialog_add_message(vd->gd, NULL, buf, NULL, TRUE); + generic_dialog_add_message(vd->gd, NULL, buf, NULL, FALSE); g_free(buf); vd->button_stop = generic_dialog_add_button(vd->gd, GTK_STOCK_STOP, NULL, editor_verbose_window_stop, FALSE);
--- a/src/filefilter.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/filefilter.c Fri Apr 13 19:06:23 2018 +0300 @@ -291,6 +291,9 @@ filter_add_if_missing("mkv", "Matroska video file", ".mkv;.webm", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); filter_add_if_missing("wmv", "Windows Media Video file", ".wmv;.asf", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); filter_add_if_missing("flv", "Flash Video file", ".flv", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); + + /* other supported formats */ + filter_add_if_missing("dds", "DirectDraw Surface", ".dds", FORMAT_CLASS_IMAGE, FALSE, FALSE, TRUE); } GList *filter_to_list(const gchar *extensions)
--- a/src/image-load.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/image-load.c Fri Apr 13 19:06:23 2018 +0300 @@ -25,6 +25,7 @@ #include "image_load_jpeg.h" #include "image_load_tiff.h" #include "image_load_bpg.h" +#include "image_load_dds.h" #include "image_load_ffmpegthumbnailer.h" #include "exif.h" @@ -647,6 +648,12 @@ } else #endif + if (il->bytes_total >= 3 && il->mapped_file[0] == 0x44 && il->mapped_file[1] == 0x44 && il->mapped_file[2] == 0x53) + { + DEBUG_1("Using dds loader"); + image_loader_backend_set_dds(&il->backend); + } + else image_loader_backend_set_default(&il->backend); il->loader = il->backend.loader_new(image_loader_area_updated_cb, image_loader_size_cb, image_loader_area_prepared_cb, il);
--- a/src/image.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/image.c Fri Apr 13 19:06:23 2018 +0300 @@ -24,6 +24,7 @@ #include "collect.h" +#include "collect-table.h" #include "color-man.h" #include "exif.h" #include "metadata.h" @@ -177,6 +178,8 @@ gchar *title = NULL; gchar *zoom = NULL; gchar *collection = NULL; + LayoutWindow *lw; + gchar *lw_ident = NULL; if (!imd->top_window) return; @@ -194,13 +197,25 @@ g_free(buf); } - title = g_strdup_printf("%s%s%s%s%s%s", + lw = layout_find_by_image(imd); + if (lw) + { + lw_ident = g_strconcat(" (", lw->options.id, ")", NULL); + } + + title = g_strdup_printf("%s%s%s%s%s%s%s", imd->title ? imd->title : "", imd->image_fd ? imd->image_fd->name : "", zoom ? zoom : "", collection ? collection : "", imd->image_fd ? " - " : "", - imd->title_right ? imd->title_right : ""); + imd->title_right ? imd->title_right : "", + options->show_window_ids ? (lw_ident ? lw_ident : "") : "" + ); + if (lw_ident) + { + g_free(lw_ident); + } gtk_window_set_title(GTK_WINDOW(imd->top_window), title); @@ -1174,9 +1189,18 @@ void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom) { + CollectWindow *cw; + if (!cd || !info || !g_list_find(cd->list, info)) return; image_change_real(imd, info->fd, cd, info, zoom); + cw = collection_window_find(cd); + if (cw) + { + collection_table_set_focus(cw->table, info); + collection_table_unselect_all(cw->table); + collection_table_select(cw->table,info); + } } CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image_load_dds.c Fri Apr 13 19:06:23 2018 +0300 @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2018 The Geeqie Team + * + * Author: Wolfgang Lieff + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + * Derived from dds_reader written by: + * Copyright (c) 2015 Kenji Sasaki + * Released under the MIT license. + * https://github.com/npedotnet/DDSReader/blob/master/LICENSE + + */ + +#include "main.h" + +#include "image-load.h" +#include "image_load_dds.h" + +typedef struct _ImageLoaderDDS ImageLoaderDDS; +struct _ImageLoaderDDS { + ImageLoaderBackendCbAreaUpdated area_updated_cb; + ImageLoaderBackendCbSize size_cb; + ImageLoaderBackendCbAreaPrepared area_prepared_cb; + gpointer data; + GdkPixbuf *pixbuf; + guint requested_width; + guint requested_height; + gboolean abort; +}; + +static void free_buffer(guchar *pixels, gpointer data) +{ + g_free(pixels); +} + +int ddsGetHeight(unsigned const char * buffer) { + return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8 | (buffer[14] & 0xFF) << 16 | (buffer[15] & 0xFF) << 24; +} + +int ddsGetWidth(unsigned const char * buffer) { + return (buffer[16] & 0xFF) | (buffer[17] & 0xFF) << 8 | (buffer[18] & 0xFF) << 16 | (buffer[19] & 0xFF) << 24; +} + +int ddsGetMipmap(unsigned const char * buffer) { + return (buffer[28] & 0xFF) | (buffer[29] & 0xFF) << 8 | (buffer[30] & 0xFF) << 16 | (buffer[31] & 0xFF) << 24; +} + +int ddsGetPixelFormatFlags(unsigned const char * buffer) { + return (buffer[80] & 0xFF) | (buffer[81] & 0xFF) << 8 | (buffer[82] & 0xFF) << 16 | (buffer[83] & 0xFF) << 24; +} + +int ddsGetFourCC(unsigned const char * buffer) { + return (buffer[84] & 0xFF) << 24 | (buffer[85] & 0xFF) << 16 | (buffer[86] & 0xFF) << 8 | (buffer[87] & 0xFF); +} + +int ddsGetBitCount(unsigned const char * buffer) { + return (buffer[88] & 0xFF) | (buffer[89] & 0xFF) << 8 | (buffer[90] & 0xFF) << 16 | (buffer[91] & 0xFF) << 24; +} + +int ddsGetRedMask(unsigned const char * buffer) { + return (buffer[92] & 0xFF) | (buffer[93] & 0xFF) << 8 | (buffer[94] & 0xFF) << 16 | (buffer[95] & 0xFF) << 24; +} + +int ddsGetGreenMask(unsigned const char * buffer) { + return (buffer[96] & 0xFF) | (buffer[97] & 0xFF) << 8 | (buffer[98] & 0xFF) << 16 | (buffer[99] & 0xFF) << 24; +} + +int ddsGetBlueMask(unsigned const char * buffer) { + return (buffer[100] & 0xFF) | (buffer[101] & 0xFF) << 8 | (buffer[102] & 0xFF) << 16 | (buffer[103] & 0xFF) << 24; +} + +int ddsGetAlphaMask(unsigned const char * buffer) { + return (buffer[104] & 0xFF) | (buffer[105] & 0xFF) << 8 | (buffer[106] & 0xFF) << 16 | (buffer[107] & 0xFF) << 24; +} + +// Image Type +#define DXT1 (0x44585431) +#define DXT2 (0x44585432) +#define DXT3 (0x44585433) +#define DXT4 (0x44585434) +#define DXT5 (0x44585435) +#define A1R5G5B5 ((1 << 16) | 2) +#define X1R5G5B5 ((2 << 16) | 2) +#define A4R4G4B4 ((3 << 16) | 2) +#define X4R4G4B4 ((4 << 16) | 2) +#define R5G6B5 ((5 << 16) | 2) +#define R8G8B8 ((1 << 16) | 3) +#define A8B8G8R8 ((1 << 16) | 4) +#define X8B8G8R8 ((2 << 16) | 4) +#define A8R8G8B8 ((3 << 16) | 4) +#define X8R8G8B8 ((4 << 16) | 4) + +// RGBA Masks +static const int A1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x8000 }; +static const int X1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x0000 }; +static const int A4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0xF000 }; +static const int X4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0x0000 }; +static const int R5G6B5_MASKS[] = { 0xF800, 0x07E0, 0x001F, 0x0000 }; +static const int R8G8B8_MASKS[] = { 0xFF0000, 0x00FF00, 0x0000FF, 0x000000 }; +static const int A8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }; +static const int X8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }; +static const int A8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }; +static const int X8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }; + +// BIT4 = 17 * index; +static const int BIT5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 }; +static const int BIT6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 }; + +static int ddsGetType(const unsigned char *buffer) { + int type = 0; + int flags = ddsGetPixelFormatFlags(buffer); + if ((flags & 0x04) != 0) { + // DXT + type = ddsGetFourCC(buffer); + } + else if ((flags & 0x40) != 0) { + // RGB + int bitCount = ddsGetBitCount(buffer); + int redMask = ddsGetRedMask(buffer); + int greenMask = ddsGetGreenMask(buffer); + int blueMask = ddsGetBlueMask(buffer); + int alphaMask = ((flags & 0x01) != 0) ? ddsGetAlphaMask(buffer) : 0; // 0x01 alpha + if (bitCount == 16) { + if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) { + // A1R5G5B5 + type = A1R5G5B5; + } + else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) { + // X1R5G5B5 + type = X1R5G5B5; + } + else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) { + // A4R4G4B4 + type = A4R4G4B4; + } + else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) { + // X4R4G4B4 + type = X4R4G4B4; + } + else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) { + // R5G6B5 + type = R5G6B5; + } + else { + // Unsupported 16bit RGB image + } + } + else if (bitCount == 24) { + if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) { + // R8G8B8 + type = R8G8B8; + } + else { + // Unsupported 24bit RGB image + } + } + else if (bitCount == 32) { + if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) { + // A8B8G8R8 + type = A8B8G8R8; + } + else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) { + // X8B8G8R8 + type = X8B8G8R8; + } + else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) { + // A8R8G8B8 + type = A8R8G8B8; + } + else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) { + // X8R8G8B8 + type = X8R8G8B8; + } + else { + // Unsupported 32bit RGB image + } + } + } + else { + // YUV or LUMINANCE image + } + return type; +} + +int ddsGetDXTColor2_1(int c0, int c1, int a) { + // 2*c0/3 + c1/3 + int r = (2 * BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 3; + int g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3; + int b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor1_1(int c0, int c1, int a) { + // (c0+c1) / 2 + int r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2; + int g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2; + int b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor1(int c, int a) { + int r = BIT5[(c & 0xFC00) >> 11]; + int g = BIT6[(c & 0x07E0) >> 5]; + int b = BIT5[(c & 0x001F)]; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor(int c0, int c1, int a, int t) { + switch (t) { + case 0: return ddsGetDXTColor1(c0, a); + case 1: return ddsGetDXTColor1(c1, a); + case 2: return (c0 > c1) ? ddsGetDXTColor2_1(c0, c1, a) : ddsGetDXTColor1_1(c0, c1, a); + case 3: return (c0 > c1) ? ddsGetDXTColor2_1(c1, c0, a) : 0; + } + return 0; +} + +guchar *ddsDecodeDXT1(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + for (int i = 0; i<h; i++) { + for (int j = 0; j<w; j++) { + int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + for (int k = 0; k<4; k++) { + if (4 * i + k >= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, 0xFF, t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, 0xFF, t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, 0xFF, t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, 0xFF, t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT3(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + int alphaTable[16]; + for (int i = 0; i<h; i++) { + for (int j = 0; j<w; j++) { + // create alpha table(4bit to 8bit) + for (int k = 0; k<4; k++) { + int a0 = (buffer[index++] & 0xFF); + int a1 = (buffer[index++] & 0xFF); + // 4bit alpha to 8bit alpha + alphaTable[4 * k + 0] = 17 * ((a0 & 0xF0) >> 4); + alphaTable[4 * k + 1] = 17 * (a0 & 0x0F); + alphaTable[4 * k + 2] = 17 * ((a1 & 0xF0) >> 4); + alphaTable[4 * k + 3] = 17 * (a1 & 0x0F); + } + int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + for (int k = 0; k<4; k++) { + if (4 * i + k >= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 0], t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 1], t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 2], t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 3], t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT2(int width, int height, const unsigned char *buffer) { + return ddsDecodeDXT3(width, height, buffer); +} + +int ddsGetDXT5Alpha(int a0, int a1, int t) { + if (a0 > a1) switch (t) { + case 0: return a0; + case 1: return a1; + case 2: return (6 * a0 + a1) / 7; + case 3: return (5 * a0 + 2 * a1) / 7; + case 4: return (4 * a0 + 3 * a1) / 7; + case 5: return (3 * a0 + 4 * a1) / 7; + case 6: return (2 * a0 + 5 * a1) / 7; + case 7: return (a0 + 6 * a1) / 7; + } + else switch (t) { + case 0: return a0; + case 1: return a1; + case 2: return (4 * a0 + a1) / 5; + case 3: return (3 * a0 + 2 * a1) / 5; + case 4: return (2 * a0 + 3 * a1) / 5; + case 5: return (a0 + 4 * a1) / 5; + case 6: return 0; + case 7: return 255; + } + return 0; +} + +guchar *ddsDecodeDXT5(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + int alphaTable[16]; + for (int i = 0; i<h; i++) { + for (int j = 0; j<w; j++) { + // create alpha table + int a0 = (buffer[index++] & 0xFF); + int a1 = (buffer[index++] & 0xFF); + int b0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3; + int b1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3; + alphaTable[0] = b0 & 0x07; + alphaTable[1] = (b0 >> 3) & 0x07; + alphaTable[2] = (b0 >> 6) & 0x07; + alphaTable[3] = (b0 >> 9) & 0x07; + alphaTable[4] = (b0 >> 12) & 0x07; + alphaTable[5] = (b0 >> 15) & 0x07; + alphaTable[6] = (b0 >> 18) & 0x07; + alphaTable[7] = (b0 >> 21) & 0x07; + alphaTable[8] = b1 & 0x07; + alphaTable[9] = (b1 >> 3) & 0x07; + alphaTable[10] = (b1 >> 6) & 0x07; + alphaTable[11] = (b1 >> 9) & 0x07; + alphaTable[12] = (b1 >> 12) & 0x07; + alphaTable[13] = (b1 >> 15) & 0x07; + alphaTable[14] = (b1 >> 18) & 0x07; + alphaTable[15] = (b1 >> 21) & 0x07; + int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + for (int k = 0; k<4; k++) { + if (4 * i + k >= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 0]), t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 2]), t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 3]), t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT4(int width, int height, const unsigned char *buffer) { + return ddsDecodeDXT5(width, height, buffer); +} + +guchar *ddsReadA1R5G5B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4*width*height); + for (int i = 0; i<height*width; i++) { + int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int r = BIT5[(rgba & A1R5G5B5_MASKS[0]) >> 10]; + int g = BIT5[(rgba & A1R5G5B5_MASKS[1]) >> 5]; + int b = BIT5[(rgba & A1R5G5B5_MASKS[2])]; + int a = 255 * ((rgba & A1R5G5B5_MASKS[3]) >> 15); + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX1R5G5B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int r = BIT5[(rgba & X1R5G5B5_MASKS[0]) >> 10]; + int g = BIT5[(rgba & X1R5G5B5_MASKS[1]) >> 5]; + int b = BIT5[(rgba & X1R5G5B5_MASKS[2])]; + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadA4R4G4B4(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8); + int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4); + int b = 17 * ((rgba & A4R4G4B4_MASKS[2])); + int a = 17 * ((rgba & A4R4G4B4_MASKS[3]) >> 12); + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX4R4G4B4(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8); + int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4); + int b = 17 * ((rgba & A4R4G4B4_MASKS[2])); + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadR5G6B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int r = BIT5[((rgba & R5G6B5_MASKS[0]) >> 11)]; + int g = BIT6[((rgba & R5G6B5_MASKS[1]) >> 5)]; + int b = BIT5[((rgba & R5G6B5_MASKS[2]))]; + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadR8G8B8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int b = buffer[index++] & 0xFF; + int g = buffer[index++] & 0xFF; + int r = buffer[index++] & 0xFF; + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadA8B8G8R8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int r = buffer[index++] & 0xFF; + int g = buffer[index++] & 0xFF; + int b = buffer[index++] & 0xFF; + int a = buffer[index++] & 0xFF; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX8B8G8R8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int r = buffer[index++] & 0xFF; + int g = buffer[index++] & 0xFF; + int b = buffer[index++] & 0xFF; + int a = 255; index++; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadA8R8G8B8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int b = buffer[index++] & 0xFF; + int g = buffer[index++] & 0xFF; + int r = buffer[index++] & 0xFF; + int a = buffer[index++] & 0xFF; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX8R8G8B8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i<height*width; i++) { + int b = buffer[index++] & 0xFF; + int g = buffer[index++] & 0xFF; + int r = buffer[index++] & 0xFF; + int a = 255; index++; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +static gboolean image_loader_dds_load (gpointer loader, const guchar *buf, gsize count, GError **error) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + int width = ddsGetWidth(buf); + int height = ddsGetHeight(buf); + int type = ddsGetType(buf); + if (type == 0) return FALSE; + { + guchar *pixels = NULL; + gint rowstride = width * 4; + switch (type) { + case DXT1: pixels = ddsDecodeDXT1(width, height, buf); break; + case DXT2: pixels = ddsDecodeDXT2(width, height, buf); break; + case DXT3: pixels = ddsDecodeDXT3(width, height, buf); break; + case DXT4: pixels = ddsDecodeDXT4(width, height, buf); break; + case DXT5: pixels = ddsDecodeDXT5(width, height, buf); break; + case A1R5G5B5: pixels = ddsReadA1R5G5B5(width, height, buf); break; + case X1R5G5B5: pixels = ddsReadX1R5G5B5(width, height, buf); break; + case A4R4G4B4: pixels = ddsReadA4R4G4B4(width, height, buf); break; + case X4R4G4B4: pixels = ddsReadX4R4G4B4(width, height, buf); break; + case R5G6B5: pixels = ddsReadR5G6B5(width, height, buf); break; + case R8G8B8: pixels = ddsReadR8G8B8(width, height, buf); break; + case A8B8G8R8: pixels = ddsReadA8B8G8R8(width, height, buf); break; + case X8B8G8R8: pixels = ddsReadX8B8G8R8(width, height, buf); break; + case A8R8G8B8: pixels = ddsReadA8R8G8B8(width, height, buf); break; + case X8R8G8B8: pixels = ddsReadX8R8G8B8(width, height, buf); break; + } + ld->pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, NULL); + ld->area_updated_cb(loader, 0, 0, width, height, ld->data); + return TRUE; + } +} + +static gpointer image_loader_dds_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data) +{ + ImageLoaderDDS *loader = g_new0(ImageLoaderDDS, 1); + loader->area_updated_cb = area_updated_cb; + loader->size_cb = size_cb; + loader->area_prepared_cb = area_prepared_cb; + loader->data = data; + return (gpointer) loader; +} + +static void image_loader_dds_set_size(gpointer loader, int width, int height) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + ld->requested_width = width; + ld->requested_height = height; +} + +static GdkPixbuf* image_loader_dds_get_pixbuf(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + return ld->pixbuf; +} + +static gchar* image_loader_dds_get_format_name(gpointer loader) +{ + return g_strdup("dds"); +} +static gchar** image_loader_dds_get_format_mime_types(gpointer loader) +{ + static gchar *mime[] = {"image/vnd-ms.dds", NULL}; + return g_strdupv(mime); +} + +static gboolean image_loader_dds_close(gpointer loader, GError **error) +{ + return TRUE; +} + +static void image_loader_dds_abort(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + ld->abort = TRUE; +} + +static void image_loader_dds_free(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + if (ld->pixbuf) g_object_unref(ld->pixbuf); + g_free(ld); +} + +void image_loader_backend_set_dds(ImageLoaderBackend *funcs) +{ + funcs->loader_new = image_loader_dds_new; + funcs->set_size = image_loader_dds_set_size; + funcs->load = image_loader_dds_load; + funcs->write = NULL; + funcs->get_pixbuf = image_loader_dds_get_pixbuf; + funcs->close = image_loader_dds_close; + funcs->abort = image_loader_dds_abort; + funcs->free = image_loader_dds_free; + funcs->get_format_name = image_loader_dds_get_format_name; + funcs->get_format_mime_types = image_loader_dds_get_format_mime_types; +} + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image_load_dds.h Fri Apr 13 19:06:23 2018 +0300 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Geeqie Team + * + * Author: Wolfgang Lieff + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef IMAGE_LOAD_DDS_H +#define IMAGE_LOAD_DDS_H + +void image_loader_backend_set_dds(ImageLoaderBackend *funcs); + +#endif + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/layout_util.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/layout_util.c Fri Apr 13 19:06:23 2018 +0300 @@ -171,6 +171,11 @@ if (x != 0 || y!= 0) { + if (event->state & GDK_SHIFT_MASK) + { + x *= 3; + y *= 3; + } keyboard_scroll_calc(&x, &y, event); layout_image_scroll(lw, x, y, (event->state & GDK_SHIFT_MASK)); } @@ -202,7 +207,7 @@ layout_image_full_screen_stop(lw); } -static void layout_menu_new_window_cb(GtkAction *action, gpointer data) +LayoutWindow *layout_menu_new_window(GtkAction *action, gpointer data) { LayoutWindow *lw = data; LayoutWindow *nw; @@ -222,6 +227,13 @@ layout_sort_set(nw, options->file_sort.method, options->file_sort.ascending); layout_set_fd(nw, lw->dir_fd); options->save_window_positions = tmp; + + return nw; +} + +static void layout_menu_new_window_cb(GtkAction *action, gpointer data) +{ + layout_menu_new_window(action, data); } static void layout_menu_new_cb(GtkAction *action, gpointer data) @@ -344,7 +356,7 @@ file_data_disable_grouping_list(layout_selection_list(lw), FALSE); } -static void layout_menu_close_cb(GtkAction *action, gpointer data) +void layout_menu_close_cb(GtkAction *action, gpointer data) { LayoutWindow *lw = data;
--- a/src/layout_util.h Sun Mar 04 19:01:45 2018 +0200 +++ b/src/layout_util.h Fri Apr 13 19:06:23 2018 +0300 @@ -72,6 +72,7 @@ void layout_exif_window_new(LayoutWindow *lw); gboolean is_help_key(GdkEventKey *event); - +LayoutWindow *layout_menu_new_window(GtkAction *action, gpointer data); +void layout_menu_close_cb(GtkAction *action, gpointer data); #endif /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/main.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/main.c Fri Apr 13 19:06:23 2018 +0300 @@ -221,6 +221,7 @@ GList *remote_errors = NULL; gboolean remote_do = FALSE; gchar *first_dir = NULL; + gchar *app_lock; command_line = g_new0(CommandLine, 1); @@ -412,6 +413,17 @@ } g_free(first_dir); + /* If Geeqie is already running, prevent a second instance + * from being started. Open a new window instead. + */ + app_lock = g_build_filename(get_rc_dir(), ".command", NULL); + if (remote_server_exists(app_lock) && !remote_do) + { + remote_do = TRUE; + remote_list = g_list_append(remote_list, "--new-window"); + } + g_free(app_lock); + if (remote_do) { if (remote_errors) @@ -782,6 +794,7 @@ CollectionData *first_collection = NULL; gchar *buf; CollectionData *cd = NULL; + gchar *app_lock; #ifdef HAVE_GTHREAD #if !GLIB_CHECK_VERSION(2,32,0)
--- a/src/options.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/options.c Fri Apr 13 19:06:23 2018 +0300 @@ -60,6 +60,7 @@ options->use_saved_window_positions_for_new_windows = FALSE; options->tools_restore_state = TRUE; options->save_dialog_window_positions = FALSE; + options->show_window_ids = FALSE; options->file_ops.confirm_delete = TRUE; options->file_ops.enable_delete_key = TRUE;
--- a/src/options.h Sun Mar 04 19:01:45 2018 +0200 +++ b/src/options.h Fri Apr 13 19:06:23 2018 +0300 @@ -57,6 +57,7 @@ gboolean use_saved_window_positions_for_new_windows; gboolean tools_restore_state; gboolean save_dialog_window_positions; + gboolean show_window_ids; gint log_window_lines;
--- a/src/preferences.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/preferences.c Fri Apr 13 19:06:23 2018 +0300 @@ -256,6 +256,7 @@ options->save_window_positions = c_options->save_window_positions; options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows; options->save_dialog_window_positions = c_options->save_dialog_window_positions; + options->show_window_ids = c_options->show_window_ids; options->image.scroll_reset_method = c_options->image.scroll_reset_method; options->image.zoom_2pass = c_options->image.zoom_2pass; options->image.fit_window_to_image = c_options->image.fit_window_to_image; @@ -1806,6 +1807,9 @@ pref_checkbox_new_int(group, _("Remember dialog window positions"), options->save_dialog_window_positions, &c_options->save_dialog_window_positions); + pref_checkbox_new_int(group, _("Show window IDs"), + options->show_window_ids, &c_options->show_window_ids); + group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL); pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
--- a/src/rcfile.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/rcfile.c Fri Apr 13 19:06:23 2018 +0300 @@ -338,6 +338,7 @@ WRITE_NL(); WRITE_BOOL(*options, use_saved_window_positions_for_new_windows); WRITE_NL(); WRITE_BOOL(*options, tools_restore_state); WRITE_NL(); WRITE_BOOL(*options, save_dialog_window_positions); + WRITE_NL(); WRITE_BOOL(*options, show_window_ids); WRITE_NL(); WRITE_UINT(*options, log_window_lines); WRITE_NL(); WRITE_BOOL(*options, log_window.timer_data); @@ -641,6 +642,7 @@ if (READ_BOOL(*options, use_saved_window_positions_for_new_windows)) continue; if (READ_BOOL(*options, tools_restore_state)) continue; if (READ_BOOL(*options, save_dialog_window_positions)) continue; + if (READ_BOOL(*options, show_window_ids)) continue; if (READ_INT(*options, log_window_lines)) continue; if (READ_BOOL(*options, log_window.timer_data)) continue;
--- a/src/remote.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/remote.c Fri Apr 13 19:06:23 2018 +0300 @@ -29,6 +29,7 @@ #include "img-view.h" #include "layout.h" #include "layout_image.h" +#include "layout_util.h" #include "misc.h" #include "pixbuf-renderer.h" #include "slideshow.h" @@ -56,6 +57,7 @@ static gint remote_client_send(RemoteConnection *rc, const gchar *text); static void gr_raise(const gchar *text, GIOChannel *channel, gpointer data); +static LayoutWindow *lw_id = NULL; /* points to the window set by the --id option */ typedef struct _RemoteClient RemoteClient; struct _RemoteClient { @@ -76,6 +78,7 @@ RemoteConnection *rc; GIOStatus status = G_IO_STATUS_NORMAL; + lw_id = NULL; rc = client->rc; if (condition & G_IO_IN) @@ -181,7 +184,7 @@ return TRUE; } -static gboolean remote_server_exists(const gchar *path) +gboolean remote_server_exists(const gchar *path) { RemoteConnection *rc; @@ -388,37 +391,70 @@ static void gr_image_next(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_next(NULL); + layout_image_next(lw_id); +} + +static void gr_new_window(const gchar *text, GIOChannel *channel, gpointer data) +{ + LayoutWindow *lw = NULL; + + if (!layout_valid(&lw)) return; + + lw_id = layout_menu_new_window(NULL, lw); +} + +static gboolean gr_close_window_cb() +{ + if (!layout_valid(&lw_id)) return FALSE; + + layout_menu_close_cb(NULL, lw_id); + + return FALSE; +} + +static void gr_close_window(const gchar *text, GIOChannel *channel, gpointer data) +{ + g_idle_add(gr_close_window_cb, NULL); } static void gr_image_prev(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_prev(NULL); + layout_image_prev(lw_id); } static void gr_image_first(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_first(NULL); + layout_image_first(lw_id); } static void gr_image_last(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_last(NULL); + layout_image_last(lw_id); } static void gr_fullscreen_toggle(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_full_screen_toggle(NULL); + layout_image_full_screen_toggle(lw_id); } static void gr_fullscreen_start(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_full_screen_start(NULL); + layout_image_full_screen_start(lw_id); } static void gr_fullscreen_stop(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_full_screen_stop(NULL); + layout_image_full_screen_stop(lw_id); +} + +static void gr_lw_id(const gchar *text, GIOChannel *channel, gpointer data) +{ + lw_id = layout_find_by_layout_id(text); + if (!lw_id) + { + log_printf("remote sent window ID that does not exist:\"%s\"\n",text); + } + layout_valid(&lw_id); } static void gr_slideshow_start_rec(const gchar *text, GIOChannel *channel, gpointer data) @@ -429,8 +465,8 @@ file_data_unref(dir_fd); if (!list) return; //printf("length: %d\n", g_list_length(list)); - layout_image_slideshow_stop(NULL); - layout_image_slideshow_start_from_list(NULL, list); + layout_image_slideshow_stop(lw_id); + layout_image_slideshow_start_from_list(lw_id, list); } static void gr_cache_thumb(const gchar *text, GIOChannel *channel, gpointer data) @@ -478,17 +514,17 @@ static void gr_slideshow_toggle(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_slideshow_toggle(NULL); + layout_image_slideshow_toggle(lw_id); } static void gr_slideshow_start(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_slideshow_start(NULL); + layout_image_slideshow_start(lw_id); } static void gr_slideshow_stop(const gchar *text, GIOChannel *channel, gpointer data) { - layout_image_slideshow_stop(NULL); + layout_image_slideshow_stop(lw_id); } static void gr_slideshow_delay(const gchar *text, GIOChannel *channel, gpointer data) @@ -542,9 +578,9 @@ gboolean popped; gboolean hidden; - if (layout_tools_float_get(NULL, &popped, &hidden) && hidden) + if (layout_tools_float_get(lw_id, &popped, &hidden) && hidden) { - layout_tools_float_set(NULL, popped, FALSE); + layout_tools_float_set(lw_id, popped, FALSE); } } @@ -553,9 +589,9 @@ gboolean popped; gboolean hidden; - if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden) + if (layout_tools_float_get(lw_id, &popped, &hidden) && !hidden) { - layout_tools_float_set(NULL, popped, TRUE); + layout_tools_float_set(lw_id, popped, TRUE); } } @@ -586,17 +622,17 @@ } else { - layout_set_path(NULL, filename); + layout_set_path(lw_id, filename); } } else if (isdir(filename)) { - layout_set_path(NULL, filename); + layout_set_path(lw_id, filename); } else { log_printf("remote sent filename that does not exist:\"%s\"\n", filename); - layout_set_path(NULL, homedir()); + layout_set_path(lw_id, homedir()); } g_free(filename); @@ -618,9 +654,9 @@ PixbufRenderer *pr; LayoutWindow *lw = NULL; - if (!layout_valid(&lw)) return; + if (!layout_valid(&lw_id)) return; - pr = (PixbufRenderer*)lw->image->pr; + pr = (PixbufRenderer*)lw_id->image->pr; if (pr) { @@ -656,11 +692,11 @@ static void gr_file_tell(const gchar *text, GIOChannel *channel, gpointer data) { - LayoutWindow *lw = NULL; /* NULL to force layout_valid() to do some magic */ - if (!layout_valid(&lw)) return; - if (image_get_path(lw->image)) + if (!layout_valid(&lw_id)) return; + + if (image_get_path(lw_id->image)) { - g_io_channel_write_chars(channel, image_get_path(lw->image), -1, NULL, NULL); + g_io_channel_write_chars(channel, image_get_path(lw_id->image), -1, NULL, NULL); g_io_channel_write_chars(channel, "\n", -1, NULL, NULL); } } @@ -771,9 +807,9 @@ { LayoutWindow *lw = NULL; - if (layout_valid(&lw)) + if (layout_valid(&lw_id)) { - gtk_window_present(GTK_WINDOW(lw->window)); + gtk_window_present(GTK_WINDOW(lw_id->window)); } } @@ -849,6 +885,9 @@ { NULL, "--list-clear", gr_list_clear, FALSE, FALSE, NULL, N_("clear command line collection list") }, { NULL, "--list-add:", gr_list_add, TRUE, FALSE, N_("<FILE>"), N_("add FILE to command line collection list") }, { NULL, "raise", gr_raise, FALSE, FALSE, NULL, N_("bring the Geeqie window to the top") }, + { NULL, "--id:", gr_lw_id, TRUE, FALSE, N_("<ID>"), N_("window id for following commands") }, + { NULL, "--new-window", gr_new_window, FALSE, FALSE, NULL, N_("new window") }, + { NULL, "--close-window", gr_close_window, FALSE, FALSE, NULL, N_("close window") }, { "-ct:", "--cache-thumbs:", gr_cache_thumb, TRUE, FALSE, N_("clear|clean"), N_("clear or clean thumbnail cache") }, { "-cs:", "--cache-shared:", gr_cache_shared, TRUE, FALSE, N_("clear|clean"), N_("clear or clean shared thumbnail cache") }, { "-cm","--cache-metadata", gr_cache_metadata, FALSE, FALSE, NULL, N_(" clean the metadata cache") },
--- a/src/remote.h Sun Mar 04 19:01:45 2018 +0200 +++ b/src/remote.h Fri Apr 13 19:06:23 2018 +0300 @@ -47,6 +47,7 @@ GList *cmd_list, GList *collection_list); RemoteConnection *remote_server_init(gchar *path, CollectionData *command_collection); +gboolean remote_server_exists(const gchar *path); #endif
--- a/src/utilops.c Sun Mar 04 19:01:45 2018 +0200 +++ b/src/utilops.c Fri Apr 13 19:06:23 2018 +0300 @@ -1132,7 +1132,7 @@ } } -static void file_util_fdlg_ok_cb(FileDialog *fdlg, gpointer data) +static void file_util_fdlg_rename_cb(FileDialog *fdlg, gpointer data) { UtilityData *ud = data; gchar *desc = NULL; @@ -1168,6 +1168,21 @@ } } +static void file_util_fdlg_ok_cb(FileDialog *fdlg, gpointer data) +{ + UtilityData *ud = data; + + file_util_dest_folder_update_path(ud); + if (isdir(ud->dest_path)) file_dialog_sync_history(fdlg, TRUE); + file_dialog_close(fdlg); + + ud->fdlg = NULL; + ud->phase = UTILITY_PHASE_ENTERING; + + file_util_dialog_run(ud); + + return; +} static void file_util_dest_folder_entry_cb(GtkWidget *entry, gpointer data) { @@ -1569,6 +1584,7 @@ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); pref_spacer(GENERIC_DIALOG(fdlg)->vbox, 0); + file_dialog_add_button(fdlg, GTK_STOCK_EDIT, "With Rename", file_util_fdlg_rename_cb, TRUE); file_dialog_add_button(fdlg, stock_id, ud->messages.title, file_util_fdlg_ok_cb, TRUE); file_dialog_add_path_widgets(fdlg, NULL, ud->dest_path, "move_copy", NULL, NULL);
--- a/web/help/GuideOptionsWindow.html Sun Mar 04 19:01:45 2018 +0200 +++ b/web/help/GuideOptionsWindow.html Fri Apr 13 19:06:23 2018 +0300 @@ -516,6 +516,19 @@ <p class="para block block-first">This will maintain dialog windows size and position between Geeqie sessions.</p> </dd> </dl></div> +<div class="block list variablelist"><dl class="variablelist"> +<dt class="term dt-first"> + <span class="guilabel">Show window IDs</span> + </dt> +<dd> + <p class="para block block-first"> + Show the window ID in the titlebar of each window. When multiple Geeqie windows are opened, this option shows a unique identifier for each window. It may be used in conjunction with the command line option: + <a class="link" href="GuideReferenceCommandLine.html#Remotecommands" title="Remote commands"> + <div dir="ltr" class=" block programlisting block-indent block-first"><pre class="programlisting">--remote --id:<ID></pre></div> + </a> + </p> + </dd> +</dl></div> </div> <div class="division section"> <a name="Size"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">11.3.2. </span>Size</span></h2></div>
--- a/web/help/GuideReferenceCommandLine.html Sun Mar 04 19:01:45 2018 +0200 +++ b/web/help/GuideReferenceCommandLine.html Fri Apr 13 19:06:23 2018 +0300 @@ -699,44 +699,62 @@ <td class="td-rowsep">Bring the geeqie window to the top</td> </tr> <tr> +<td class="td-colsep td-rowsep"></td> +<td class="td-colsep td-rowsep">--id:<ID></td> +<td class="td-rowsep"> + Window ID for following commands + <a name="-noteref-ref3"></a><sup><a class="footnote" href="#ref3">2</a></sup> + </td> +</tr> +<tr class="tr-shade"> +<td class="td-colsep td-rowsep"></td> +<td class="td-colsep td-rowsep">--new-window</td> +<td class="td-rowsep">Open new window</td> +</tr> +<tr> +<td class="td-colsep td-rowsep"></td> +<td class="td-colsep td-rowsep">--close-window</td> +<td class="td-rowsep">Close window</td> +</tr> +<tr class="tr-shade"> <td class="td-colsep td-rowsep">-ct:clear|clean</td> <td class="td-colsep td-rowsep">--cache-thumbs:clear|clean</td> <td class="td-rowsep">clear or clean thumbnail cache</td> </tr> -<tr class="tr-shade"> +<tr> <td class="td-colsep td-rowsep">-cs:clear|clean</td> <td class="td-colsep td-rowsep">--cache-shared:clear|clean</td> <td class="td-rowsep">clear or clean shared thumbnail cache</td> </tr> -<tr> +<tr class="tr-shade"> <td class="td-colsep td-rowsep">-cm</td> <td class="td-colsep td-rowsep">--cache-metadata</td> <td class="td-rowsep">clean the metadata cache</td> </tr> -<tr class="tr-shade"> +<tr> <td class="td-colsep td-rowsep">-cr:<folder></td> <td class="td-colsep td-rowsep">--cache-render:<folder></td> <td class="td-rowsep">render thumbnails</td> </tr> -<tr> +<tr class="tr-shade"> <td class="td-colsep td-rowsep">-crr:<folder></td> <td class="td-colsep td-rowsep">--cache-render-recurse:<folder></td> <td class="td-rowsep">render thumbnails recursively</td> </tr> -<tr class="tr-shade"> +<tr> <td class="td-colsep td-rowsep">-crs:<folder></td> <td class="td-colsep td-rowsep">--cache-render-shared:<folder></td> <td class="td-rowsep"> render thumbnails - <a name="-noteref-ref2"></a><sup><a class="footnote" href="#ref2">2</a></sup> + <a name="-noteref-ref2"></a><sup><a class="footnote" href="#ref2">3</a></sup> </td> </tr> -<tr> +<tr class="tr-shade"> <td class="td-colsep td-rowsep">-crsr:<folder></td> <td class="td-colsep td-rowsep">--cache-render-shared-recurse:<folder></td> <td class="td-rowsep">render thumbnails recursively</td> </tr> -<tr class="tr-shade"> +<tr> <td class="td-colsep"></td> <td class="td-colsep">--lua:<file>,<lua script></td> <td>run lua script on file</td> @@ -749,7 +767,11 @@ <div class="footnote"> <a name="ref1"></a><span class="footnote-number"><a class="footnote-ref" href="#-noteref-ref1">1</a></span>The name of a collection, with or without either path or extension (.gqv) may be used. If a path is not used and there is a name conflict with a file or folder, that will take precedence.</div> <div class="footnote"> -<a name="ref2"></a><span class="footnote-number"><a class="footnote-ref" href="#-noteref-ref2">2</a></span> +<a name="ref3"></a><span class="footnote-number"><a class="footnote-ref" href="#-noteref-ref3">2</a></span> + <p class="para block block-first">The ID is shown in the titlebar of the window. If multiple windows are open, it can be used to direct commands to a particular window e.g. --remote --id:main --tell</p> + </div> +<div class="footnote"> +<a name="ref2"></a><span class="footnote-number"><a class="footnote-ref" href="#-noteref-ref2">3</a></span> <p class="para block block-first">If standard thumbnail cache is not enabled, this command will be ignored.</p> </div> </div>
--- a/web/help/GuideReferenceSupportedFormats.html Sun Mar 04 19:01:45 2018 +0200 +++ b/web/help/GuideReferenceSupportedFormats.html Fri Apr 13 19:06:23 2018 +0300 @@ -458,7 +458,7 @@ <li class="linktrail linktrail-first"><a class="linktrail" href="GuideIndex.html" title="The Geeqie User Manual">The Geeqie User Manual</a></li> <li class="linktrail linktrail-last"><a class="linktrail" href="GuideReference.html" title="Reference">Reference</a></li> </ul> -<p class="para block block-first">3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.</p> +<p class="para block block-first">3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DDS, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.</p> <p class="para block"> Refer to <a class="link" href="GuideReferencePixbufLoaders.html" title="Additional pixbuf loaders">Additional pixbuf loaders</a>