mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-18 12:00:31 +01:00
util/wmiv: an image viewer using wrlib
This patch brings wmiv, a fast image viewer using wrlib.
This commit is contained in:
committed by
Carlos R. Mafra
parent
66556c421d
commit
0c151a55f4
@@ -158,6 +158,10 @@ AS_IF([test "x$debug" = "xyes"],
|
||||
AX_CFLAGS_GCC_OPTION([-Wno-deprecated-declarations])
|
||||
])
|
||||
|
||||
dnl Posix thread
|
||||
dnl =================
|
||||
AX_PTHREAD
|
||||
|
||||
|
||||
dnl Tracking on what is detected for final status
|
||||
dnl =============================================
|
||||
|
||||
332
m4/ax_pthread.m4
Normal file
332
m4/ax_pthread.m4
Normal file
@@ -0,0 +1,332 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
# PTHREAD_CFLAGS.
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# Updated for Autoconf 2.68 by Daniel Richard G.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case ${host_os} in
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
darwin*)
|
||||
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clang doesn't consider unrecognized options an error unless we specify
|
||||
# -Werror. We throw in some extra Clang-specific options to ensure that
|
||||
# this doesn't happen for GCC, which also accepts -Werror.
|
||||
|
||||
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_extra_flags="-Werror"
|
||||
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ax_pthread_extra_flags=
|
||||
AC_MSG_RESULT([no])])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT([$attr_name])
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case ${host_os} in
|
||||
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||
osf* | hpux*) flag="-D_REENTRANT";;
|
||||
solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
# TODO: What about Clang on Solaris?
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$flag])
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != xyes; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_POP
|
||||
])dnl AX_PTHREAD
|
||||
@@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS =
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
|
||||
bin_PROGRAMS = wxcopy wxpaste wdwrite wdread getstyle setstyle convertfonts \
|
||||
seticons geticonset wmsetbg wmagnify wmgenmenu wmmenugen
|
||||
seticons geticonset wmsetbg wmagnify wmgenmenu wmmenugen wmiv
|
||||
|
||||
bin_SCRIPTS = wmaker.inst wm-oldmenu2new wkdemenu.pl
|
||||
|
||||
@@ -70,6 +70,13 @@ wmmenugen_SOURCES = wmmenugen.c wmmenugen.h wmmenugen_misc.c \
|
||||
wmmenugen_parse_wmconfig.c \
|
||||
wmmenugen_parse_xdg.c
|
||||
|
||||
wmiv_LDADD = \
|
||||
$(top_builddir)/wrlib/libwraster.la \
|
||||
@XLFLAGS@ @XLIBS@ \
|
||||
@GFXLIBS@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
|
||||
wmiv_SOURCES = wmiv.c wmiv.h
|
||||
|
||||
CLEANFILES = wmaker.inst
|
||||
|
||||
wmaker.inst: $(srcdir)/wmaker.inst.in ./Makefile
|
||||
|
||||
815
util/wmiv.c
Executable file
815
util/wmiv.c
Executable file
@@ -0,0 +1,815 @@
|
||||
/*
|
||||
* Window Maker window manager
|
||||
*
|
||||
* Copyright (c) 2014 Window Maker Team - David Maciejak
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include "wraster.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include "config.h"
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_XPM
|
||||
extern int XpmCreatePixmapFromData(Display *, Drawable, char **, Pixmap *, Pixmap *, void *);
|
||||
/* this is the icon from eog project
|
||||
git.gnome.org/browse/eog
|
||||
*/
|
||||
#include "wmiv.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG 0
|
||||
#define FILE_SEPARATOR '/'
|
||||
|
||||
Display *dpy;
|
||||
Window win;
|
||||
RContext *ctx;
|
||||
RImage *img;
|
||||
Pixmap pix;
|
||||
|
||||
const char *APPNAME = "wmiv";
|
||||
int APPVERSION_MAJOR = 0;
|
||||
int APPVERSION_MINOR = 6;
|
||||
int NEXT = 0;
|
||||
int PREV = 1;
|
||||
float zoom_factor = 0;
|
||||
int max_width = 0;
|
||||
int max_height = 0;
|
||||
|
||||
Bool fullscreen_flag = False;
|
||||
Bool focus = False;
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
Bool diaporama_flag = False;
|
||||
int diaporama_delay = 5;
|
||||
pthread_t tid = 0;
|
||||
#endif
|
||||
XTextProperty title_property;
|
||||
XTextProperty icon_property;
|
||||
unsigned current_index = 1;
|
||||
unsigned max_index = 1;
|
||||
|
||||
RColor lightGray;
|
||||
RColor darkGray;
|
||||
RColor black;
|
||||
RColor red;
|
||||
|
||||
typedef struct link link_t;
|
||||
struct link {
|
||||
const void * data;
|
||||
link_t *prev;
|
||||
link_t *next;
|
||||
};
|
||||
|
||||
typedef struct linked_list {
|
||||
int count;
|
||||
link_t *first;
|
||||
link_t *last;
|
||||
} linked_list_t;
|
||||
|
||||
linked_list_t list;
|
||||
link_t *current_link;
|
||||
|
||||
/*
|
||||
change_title: used to change window title
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int change_title(XTextProperty *prop, char *filename) {
|
||||
char *combined_title = NULL;
|
||||
if (!asprintf(&combined_title, "%s - %u/%u - %s", APPNAME, current_index, max_index, filename))
|
||||
if (!asprintf(&combined_title, "%s - %u/%u", APPNAME, current_index, max_index))
|
||||
return EXIT_FAILURE;
|
||||
XStringListToTextProperty(&combined_title, 1, prop);
|
||||
XSetWMName(dpy, win, prop);
|
||||
if (prop->value)
|
||||
XFree(prop->value);
|
||||
free(combined_title);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
rescale_image: used to rescale the current image based on the screen size
|
||||
return EXIT_SUCCESS on success
|
||||
*/
|
||||
int rescale_image() {
|
||||
long final_width = img->width;
|
||||
long final_height = img->height;
|
||||
|
||||
/* check if there is already a zoom factor applied */
|
||||
if (zoom_factor != 0) {
|
||||
final_width = img->width + (int)(img->width * zoom_factor);
|
||||
final_height = img->height + (int)(img->height * zoom_factor);
|
||||
}
|
||||
if ((max_width < final_width) || (max_height < final_height)) {
|
||||
long val = 0;
|
||||
if (final_width > final_height) {
|
||||
val = final_height * max_width / final_width;
|
||||
final_width = final_width * val / final_height;
|
||||
final_height = val;
|
||||
if (val > max_height) {
|
||||
val = final_width * max_height / final_height;
|
||||
final_height = final_height * val / final_width;
|
||||
final_width = val;
|
||||
}
|
||||
} else {
|
||||
val = final_width * max_height / final_height;
|
||||
final_height = final_height * val / final_width;
|
||||
final_width = val;
|
||||
if (val > max_width) {
|
||||
val = final_height * max_width / final_width;
|
||||
final_width = final_width * val / final_height;
|
||||
final_height = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((final_width != img->width) || (final_height != img->height)) {
|
||||
RImage *old_img = img;
|
||||
img = RScaleImage(img, final_width, final_height);
|
||||
if (!img) {
|
||||
img = old_img;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
RReleaseImage(old_img);
|
||||
}
|
||||
if (!RConvertImage(ctx, img, &pix)) {
|
||||
fprintf(stderr, "%s\n", RMessageForError(RErrorCode));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
maximize_image: find the best image size for the current display
|
||||
return EXIT_SUCCESS on success
|
||||
*/
|
||||
int maximize_image() {
|
||||
rescale_image();
|
||||
XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, max_width/2-img->width/2, max_height/2-img->height/2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
merge_with_background: merge the current image with with a checkboard background
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int merge_with_background(RImage *i) {
|
||||
if (i) {
|
||||
RImage *back;
|
||||
back = RCreateImage(i->width, i->height, True);
|
||||
if (back) {
|
||||
int opaq = 255;
|
||||
int x=0, y=0;
|
||||
|
||||
RFillImage(back, &lightGray);
|
||||
for (x=0; x <= i->width; x+=8) {
|
||||
if (x/8 % 2)
|
||||
y = 8;
|
||||
else
|
||||
y = 0;
|
||||
for (; y <= i->height; y+=16)
|
||||
ROperateRectangle(back, RAddOperation, x,y,x+8,y+8, &darkGray);
|
||||
}
|
||||
|
||||
RCombineImagesWithOpaqueness(i, back, opaq);
|
||||
RReleaseImage(back);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
draw_failed_image: create a red crossed image to indicate an error loading file
|
||||
return the image on success, NULL on failure
|
||||
|
||||
*/
|
||||
RImage* draw_failed_image() {
|
||||
RImage *failed_image = NULL;
|
||||
XWindowAttributes attr;
|
||||
|
||||
if (win && (XGetWindowAttributes(dpy, win, &attr) >= 0)) {
|
||||
failed_image = RCreateImage(attr.width, attr.height, False);
|
||||
} else {
|
||||
failed_image = RCreateImage(50, 50, False);
|
||||
}
|
||||
if (!failed_image)
|
||||
return NULL;
|
||||
|
||||
RFillImage(failed_image, &black);
|
||||
ROperateLine(failed_image, RAddOperation, 0, 0, failed_image->width, failed_image->height, &red);
|
||||
ROperateLine(failed_image, RAddOperation, 0, failed_image->height, failed_image->width, 0, &red);
|
||||
|
||||
return failed_image;
|
||||
}
|
||||
|
||||
/*
|
||||
full_screen: sending event to the window manager to switch from/to full screen mode
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int full_screen() {
|
||||
XEvent xev;
|
||||
|
||||
Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", True);
|
||||
Atom fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", True);
|
||||
long mask = SubstructureNotifyMask;
|
||||
|
||||
if (fullscreen_flag) {
|
||||
fullscreen_flag = False;
|
||||
zoom_factor = 0;
|
||||
} else {
|
||||
fullscreen_flag = True;
|
||||
zoom_factor = 1000;
|
||||
}
|
||||
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.display = dpy;
|
||||
xev.xclient.window = win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = fullscreen_flag;
|
||||
xev.xclient.data.l[1] = fullscreen;
|
||||
|
||||
if (!XSendEvent(dpy, DefaultRootWindow(dpy), False, mask, &xev)) {
|
||||
fprintf(stderr, "Error: sending fullscreen event to xserver\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
zoom_in_out: apply a zoom factor on the current image
|
||||
arg: 1 to zoom in, 0 to zoom out
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int zoom_in_out(int z) {
|
||||
RImage *old_img = img;
|
||||
RImage *tmp = RLoadImage(ctx, current_link->data, 0);
|
||||
if (!tmp)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (z) {
|
||||
zoom_factor += 0.2;
|
||||
img = RScaleImage(tmp, tmp->width + (int)(tmp->width * zoom_factor), tmp->height + (int)(tmp->height * zoom_factor));
|
||||
if (!img) {
|
||||
img = old_img;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else {
|
||||
zoom_factor -= 0.2;
|
||||
int new_width = tmp->width + (int) (tmp->width * zoom_factor);
|
||||
int new_height = tmp->height + (int)(tmp->height * zoom_factor);
|
||||
if ((new_width <= 0) || (new_height <= 0)) {
|
||||
zoom_factor += 0.2;
|
||||
RReleaseImage(tmp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
img = RScaleImage(tmp, new_width, new_height);
|
||||
if (!img) {
|
||||
img = old_img;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
RReleaseImage(old_img);
|
||||
RReleaseImage(tmp);
|
||||
XFreePixmap(dpy, pix);
|
||||
|
||||
merge_with_background(img);
|
||||
if (!RConvertImage(ctx, img, &pix)) {
|
||||
fprintf(stderr, "%s\n", RMessageForError(RErrorCode));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
XResizeWindow(dpy, win, img->width, img->height);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
zoom_in: transitional fct used to call zoom_in_out with zoom in flag
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int zoom_in() {
|
||||
return zoom_in_out(1);
|
||||
}
|
||||
|
||||
/*
|
||||
zoom_out: transitional fct used to call zoom_in_out with zoom out flag
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int zoom_out() {
|
||||
return zoom_in_out(0);
|
||||
}
|
||||
|
||||
/*
|
||||
change_image: load previous or next image
|
||||
arg: way which could be PREV or NEXT constant
|
||||
return EXIT_SUCCESS on success, 1 on failure
|
||||
*/
|
||||
int change_image(int way) {
|
||||
if (img && current_link) {
|
||||
int old_img_width = img->width;
|
||||
int old_img_height = img->height;
|
||||
|
||||
RReleaseImage(img);
|
||||
|
||||
if (way == NEXT) {
|
||||
current_link = current_link->next;
|
||||
current_index++;
|
||||
} else {
|
||||
current_link = current_link->prev;
|
||||
current_index--;
|
||||
}
|
||||
if (current_link == NULL) {
|
||||
if (way == NEXT) {
|
||||
current_link = list.first;
|
||||
current_index = 1;
|
||||
} else {
|
||||
current_link = list.last;
|
||||
current_index = max_index;
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
fprintf(stderr, "current file is> %s\n", (char *)current_link->data);
|
||||
img = RLoadImage(ctx, current_link->data, 0);
|
||||
|
||||
if (!img) {
|
||||
fprintf(stderr, "Error: %s %s\n", (char *)current_link->data, RMessageForError(RErrorCode));
|
||||
img = draw_failed_image();
|
||||
} else {
|
||||
merge_with_background(img);
|
||||
}
|
||||
rescale_image();
|
||||
if (!fullscreen_flag) {
|
||||
if ((old_img_width != img->width) || (old_img_height != img->height)) {
|
||||
XResizeWindow(dpy, win, img->width, img->height);
|
||||
} else {
|
||||
XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, 0, 0);
|
||||
}
|
||||
change_title(&title_property, (char *)current_link->data);
|
||||
} else {
|
||||
XClearWindow(dpy, win);
|
||||
XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, max_width/2-img->width/2, max_height/2-img->height/2);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
/*
|
||||
diaporama: send a xevent to display the next image at every delay set to diaporama_delay
|
||||
arg: not used
|
||||
return void
|
||||
*/
|
||||
void* diaporama(void *arg) {
|
||||
(void) arg;
|
||||
|
||||
XKeyEvent event;
|
||||
event.display = dpy;
|
||||
event.window = win;
|
||||
event.root = DefaultRootWindow(dpy);
|
||||
event.subwindow = None;
|
||||
event.time = CurrentTime;
|
||||
event.x = 1;
|
||||
event.y = 1;
|
||||
event.x_root = 1;
|
||||
event.y_root = 1;
|
||||
event.same_screen = True;
|
||||
event.keycode = XKeysymToKeycode(dpy, XK_Right);
|
||||
event.state = 0;
|
||||
event.type = KeyPress;
|
||||
|
||||
while(diaporama_flag) {
|
||||
int r;
|
||||
r = XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
|
||||
if (!r)
|
||||
fprintf(stderr, "Error sending event\n");
|
||||
XFlush(dpy);
|
||||
/* default sleep time between moving to next image */
|
||||
sleep(diaporama_delay);
|
||||
}
|
||||
tid = 0;
|
||||
return arg;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
linked_list_init: init the linked list
|
||||
*/
|
||||
void linked_list_init (linked_list_t *list) {
|
||||
list->first = list->last = 0;
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
linked_list_add: add an element to the linked list
|
||||
return EXIT_SUCCESS on success, 1 otherwise
|
||||
*/
|
||||
int linked_list_add (linked_list_t *list, const void *data) {
|
||||
link_t *link;
|
||||
|
||||
/* calloc sets the "next" field to zero. */
|
||||
link = calloc (1, sizeof (link_t));
|
||||
if (! link) {
|
||||
fprintf (stderr, "calloc failed.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
link->data = data;
|
||||
if (list->last) {
|
||||
/* Join the two final links together. */
|
||||
list->last->next = link;
|
||||
link->prev = list->last;
|
||||
list->last = link;
|
||||
} else {
|
||||
list->first = link;
|
||||
list->last = link;
|
||||
}
|
||||
list->count++;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
linked_list_free: deallocate the whole linked list
|
||||
*/
|
||||
void linked_list_free (linked_list_t *list) {
|
||||
link_t *link;
|
||||
link_t *next;
|
||||
for (link = list->first; link; link = next) {
|
||||
/* Store the next value so that we don't access freed memory. */
|
||||
next = link->next;
|
||||
if (link->data)
|
||||
free((char *)link->data);
|
||||
free (link);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
connect_dir: list and sort by name all files from a given directory
|
||||
arg: the directory path that contains images, the linked list where to add the new file refs
|
||||
return: the first argument of the list or NULL on failure
|
||||
*/
|
||||
link_t* connect_dir(char *dirpath, linked_list_t *li) {
|
||||
struct dirent **dir;
|
||||
int dv, idx;
|
||||
char path[PATH_MAX] = "";
|
||||
|
||||
if (!dirpath)
|
||||
return NULL;
|
||||
|
||||
dv = scandir(dirpath, &dir, 0, alphasort);
|
||||
if (dv < 0) {
|
||||
/* maybe it's a file */
|
||||
struct stat stDirInfo;
|
||||
if (lstat(dirpath, &stDirInfo) == 0) {
|
||||
linked_list_add (li, strdup(dirpath));
|
||||
return li->first;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
for (idx = 0; idx < dv; idx++) {
|
||||
struct stat stDirInfo;
|
||||
if (dirpath[strlen(dirpath)-1] == FILE_SEPARATOR)
|
||||
snprintf(path, PATH_MAX, "%s%s", dirpath, dir[idx]->d_name);
|
||||
else
|
||||
snprintf(path, PATH_MAX, "%s%c%s", dirpath, FILE_SEPARATOR, dir[idx]->d_name);
|
||||
|
||||
free(dir[idx]);
|
||||
if ((lstat(path, &stDirInfo) == 0) && !S_ISDIR(stDirInfo.st_mode)) {
|
||||
linked_list_add (li, strdup(path));
|
||||
}
|
||||
}
|
||||
free(dir);
|
||||
return li->first;
|
||||
}
|
||||
|
||||
/*
|
||||
main
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
int option = -1;
|
||||
RContextAttributes attr;
|
||||
XEvent e;
|
||||
KeySym keysym;
|
||||
char *reading_filename = "";
|
||||
int screen, file_i;
|
||||
int quit = 0;
|
||||
XClassHint *class_hints;
|
||||
XSizeHints *size_hints;
|
||||
XWMHints *win_hints;
|
||||
#ifdef USE_XPM
|
||||
Pixmap icon_pixmap, icon_shape;
|
||||
#endif
|
||||
|
||||
if (!(class_hints = XAllocClassHint())) {
|
||||
fprintf(stderr, "Error: failure allocating memory\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
class_hints->res_name = (char *)APPNAME;
|
||||
class_hints->res_class = "default";
|
||||
|
||||
/* init colors */
|
||||
lightGray.red = lightGray.green = lightGray.blue = 211;
|
||||
darkGray.red = darkGray.green = darkGray.blue = 169;
|
||||
lightGray.alpha = darkGray.alpha = 1;
|
||||
black.red = black.green = black.blue = 0;
|
||||
red.red = 255;
|
||||
red.green = red.blue = 0;
|
||||
|
||||
if ((option = getopt(argc, argv, "hv")) != -1) {
|
||||
switch (option) {
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: %s [image(s)|directory]\n"
|
||||
"Keys:\n"
|
||||
"+: zoom in\n"
|
||||
"-: zoom out\n"
|
||||
"esc: actual size\n"
|
||||
#ifdef HAVE_PTHREAD
|
||||
"d: launch diaporama mode\n"
|
||||
#endif
|
||||
"q: quit\n"
|
||||
"right: next image\n"
|
||||
"left: previous image\n"
|
||||
"up: first image\n"
|
||||
"down: last image\n",
|
||||
argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
case 'v':
|
||||
fprintf(stderr, "%s version %d.%d\n", APPNAME, APPVERSION_MAJOR, APPVERSION_MINOR);
|
||||
return EXIT_SUCCESS;
|
||||
case '?':
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
linked_list_init (&list);
|
||||
|
||||
dpy = XOpenDisplay(NULL);
|
||||
if (!dpy) {
|
||||
fprintf(stderr, "Error: can't open display");
|
||||
linked_list_free (&list);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
screen = DefaultScreen(dpy);
|
||||
max_width = DisplayWidth(dpy, screen);
|
||||
max_height = DisplayHeight(dpy, screen);
|
||||
|
||||
attr.flags = RC_RenderMode | RC_ColorsPerChannel;
|
||||
attr.render_mode = RDitheredRendering;
|
||||
attr.colors_per_channel = 4;
|
||||
ctx = RCreateContext(dpy, DefaultScreen(dpy), &attr);
|
||||
|
||||
if (argc < 2) {
|
||||
argv[1] = ".";
|
||||
argc = 2;
|
||||
}
|
||||
|
||||
for (file_i = 1; file_i < argc; file_i++) {
|
||||
current_link = connect_dir(argv[file_i], &list);
|
||||
if (current_link) {
|
||||
reading_filename = (char *)current_link->data;
|
||||
max_index = list.count;
|
||||
}
|
||||
}
|
||||
|
||||
img = RLoadImage(ctx, reading_filename, 0);
|
||||
|
||||
if (!img) {
|
||||
fprintf(stderr, "Error: %s %s\n", reading_filename, RMessageForError(RErrorCode));
|
||||
img = draw_failed_image();
|
||||
if (!current_link)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
merge_with_background(img);
|
||||
rescale_image();
|
||||
|
||||
if (DEBUG)
|
||||
fprintf(stderr, "display size: %dx%d\n", max_width, max_height);
|
||||
|
||||
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, img->width, img->height, 0, 0, BlackPixel(dpy, screen));
|
||||
XSelectInput(dpy, win, KeyPressMask|StructureNotifyMask|ExposureMask|ButtonPressMask|FocusChangeMask);
|
||||
|
||||
if (!(size_hints = XAllocSizeHints())) {
|
||||
fprintf(stderr, "Error: failure allocating memory\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
size_hints->width = img->width;
|
||||
size_hints->height = img->height;
|
||||
|
||||
Atom delWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
|
||||
XSetWMProtocols(dpy, win, &delWindow, 1);
|
||||
change_title(&title_property, reading_filename);
|
||||
|
||||
win_hints = XAllocWMHints();
|
||||
if (win_hints) {
|
||||
win_hints->flags = StateHint|InputHint|WindowGroupHint;
|
||||
|
||||
#ifdef USE_XPM
|
||||
if ((XpmCreatePixmapFromData(dpy, win, wmiv_xpm, &icon_pixmap, &icon_shape, NULL)) == 0) {
|
||||
win_hints->flags |= IconPixmapHint|IconMaskHint|IconPositionHint;
|
||||
win_hints->icon_pixmap = icon_pixmap;
|
||||
win_hints->icon_mask = icon_shape;
|
||||
win_hints->icon_x = 0;
|
||||
win_hints->icon_y = 0;
|
||||
}
|
||||
#endif
|
||||
win_hints->initial_state = NormalState;
|
||||
win_hints->input = True;
|
||||
win_hints->window_group = win;
|
||||
XStringListToTextProperty((char **)&APPNAME, 1, &icon_property);
|
||||
XSetWMProperties(dpy, win, NULL, &icon_property, argv, argc, size_hints, win_hints, class_hints);
|
||||
if (icon_property.value)
|
||||
XFree(icon_property.value);
|
||||
XFree(win_hints);
|
||||
XFree(class_hints);
|
||||
XFree(size_hints);
|
||||
|
||||
}
|
||||
XMapWindow(dpy, win);
|
||||
XFlush(dpy);
|
||||
XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, 0, 0);
|
||||
|
||||
while (!quit) {
|
||||
XNextEvent(dpy, &e);
|
||||
if (e.type == ClientMessage) {
|
||||
if (e.xclient.data.l[0] == delWindow)
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
if (e.type == FocusIn) {
|
||||
focus = True;
|
||||
continue;
|
||||
}
|
||||
if (e.type == FocusOut) {
|
||||
focus = False;
|
||||
continue;
|
||||
}
|
||||
if (!fullscreen_flag && (e.type == Expose)) {
|
||||
XExposeEvent xev = e.xexpose;
|
||||
if (xev.count == 0)
|
||||
XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, 0, 0);
|
||||
continue;
|
||||
}
|
||||
if (!fullscreen_flag && e.type == ConfigureNotify) {
|
||||
XConfigureEvent xce = e.xconfigure;
|
||||
if (xce.width != img->width || xce.height != img->height) {
|
||||
RImage *old_img = img;
|
||||
img = RLoadImage(ctx, current_link->data, 0);
|
||||
if (!img) {
|
||||
/* keep the old img and window size */
|
||||
img = old_img;
|
||||
XResizeWindow(dpy, win, img->width, img->height);
|
||||
} else {
|
||||
img = RScaleImage(img, xce.width, xce.height);
|
||||
if (!img) {
|
||||
img = old_img;
|
||||
XResizeWindow(dpy, win, img->width, img->height);
|
||||
} else {
|
||||
merge_with_background(img);
|
||||
if (RConvertImage(ctx, img, &pix))
|
||||
RReleaseImage(old_img);
|
||||
XResizeWindow(dpy, win, img->width, img->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fullscreen_flag && e.type == ConfigureNotify) {
|
||||
maximize_image();
|
||||
continue;
|
||||
}
|
||||
if (e.type == ButtonPress) {
|
||||
switch(e.xbutton.button) {
|
||||
case Button1: {
|
||||
if (focus) {
|
||||
if (img && (e.xbutton.x > img->width/2))
|
||||
change_image(NEXT);
|
||||
else
|
||||
change_image(PREV);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Button4:
|
||||
zoom_in();
|
||||
break;
|
||||
case Button5:
|
||||
zoom_out();
|
||||
break;
|
||||
case 8:
|
||||
change_image(PREV);
|
||||
break;
|
||||
case 9:
|
||||
change_image(NEXT);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (e.type == KeyPress) {
|
||||
keysym = XkbKeycodeToKeysym(dpy, e.xkey.keycode, 0, e.xkey.state & ShiftMask?1:0);
|
||||
#ifdef HAVE_PTHREAD
|
||||
if (keysym != XK_Right)
|
||||
diaporama_flag = False;
|
||||
#endif
|
||||
switch (keysym) {
|
||||
case XK_Right:
|
||||
change_image(NEXT);
|
||||
break;
|
||||
case XK_Left:
|
||||
change_image(PREV);
|
||||
break;
|
||||
case XK_Up:
|
||||
if (current_link) {
|
||||
current_link = list.last;
|
||||
change_image(NEXT);
|
||||
}
|
||||
break;
|
||||
case XK_Down:
|
||||
if (current_link) {
|
||||
current_link = list.first;
|
||||
change_image(PREV);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_PTHREAD
|
||||
case XK_F5:
|
||||
case XK_d:
|
||||
if (!tid) {
|
||||
if (current_link && !diaporama_flag) {
|
||||
diaporama_flag = True;
|
||||
pthread_create(&tid, NULL, &diaporama, NULL);
|
||||
} else {
|
||||
fprintf(stderr, "Can't use diaporama mode, need a picture directory\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case XK_q:
|
||||
quit = 1;
|
||||
break;
|
||||
case XK_Escape:
|
||||
if (!fullscreen_flag) {
|
||||
zoom_factor = -0.2;
|
||||
/* zoom_in will increase the zoom factor by 0.2 */
|
||||
zoom_in();
|
||||
} else {
|
||||
/* we are in fullscreen mode already, want to return to normal size */
|
||||
full_screen();
|
||||
}
|
||||
break;
|
||||
case XK_plus:
|
||||
zoom_in();
|
||||
break;
|
||||
case XK_minus:
|
||||
zoom_out();
|
||||
break;
|
||||
case XK_F11:
|
||||
case XK_f:
|
||||
full_screen();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (img)
|
||||
RReleaseImage(img);
|
||||
if (pix)
|
||||
XFreePixmap(dpy, pix);
|
||||
#ifdef USE_XPM
|
||||
if (icon_pixmap)
|
||||
XFreePixmap(dpy, icon_pixmap);
|
||||
if (icon_shape)
|
||||
XFreePixmap(dpy, icon_shape);
|
||||
#endif
|
||||
linked_list_free(&list);
|
||||
RDestroyContext(ctx);
|
||||
RShutdown();
|
||||
XCloseDisplay(dpy);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
1279
util/wmiv.h
Executable file
1279
util/wmiv.h
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user