-/* photopile, Copyright (c) 2008-2011 Jens Kilian <jjk@acm.org>
+/* photopile, Copyright (c) 2008-2015 Jens Kilian <jjk@acm.org>
* Based on carousel, Copyright (c) 2005-2008 Jamie Zawinski <jwz@jwz.org>
* Loads a sequence of images and shuffles them into a pile.
*
* implied warranty.
*/
-#define DEF_FONT "-*-helvetica-bold-r-normal-*-240-*"
+#define DEF_FONT "-*-helvetica-bold-r-normal-*-*-480-*-*-*-*-*-*"
#define DEFAULTS "*count: 7 \n" \
"*delay: 10000 \n" \
"*wireframe: False \n" \
"*font: " DEF_FONT "\n" \
"*desktopGrabber: xscreensaver-getimage -no-desktop %s\n" \
"*grabDesktopImages: False \n" \
- "*chooseRandomImages: True \n"
+ "*chooseRandomImages: True \n" \
+ "*suppressRotationAnimation: True\n" \
# define refresh_photopile 0
# define release_photopile 0
#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))
-#ifndef HAVE_COCOA
+#ifndef HAVE_JWXYZ
# include <X11/Intrinsic.h> /* for XrmDatabase in -debug mode */
#endif
#include <math.h>
} image;
-typedef enum { EARLY, IN, NORMAL, LOADING, SHUFFLE } fade_mode;
+typedef enum { EARLY, SHUFFLE, NORMAL, LOADING } fade_mode;
static int fade_ticks = 60;
typedef struct {
static Bool mipmap_p; /* Use mipmaps instead of single textures. */
static Bool titles_p; /* Display image titles. */
static Bool polaroid_p; /* Use instant-film look for images. */
-static Bool clip_p; /* Clip images instead of scaling for -polaroid. */static Bool shadows_p; /* Draw drop shadows. */
+static Bool clip_p; /* Clip images instead of scaling for -polaroid. */
+static Bool shadows_p; /* Draw drop shadows. */
static Bool debug_p; /* Be loud and do weird things. */
for (i = 0; i < MI_COUNT(mi)+1; ++i)
{
image *frame = ss->frames + i;
- GLfloat d = sqrt(frame->w*frame->w + frame->h*frame->h);
+ GLfloat w = frame->w;
+ GLfloat h = frame->h;
+ GLfloat d = sqrt(w*w + h*h);
GLfloat leave = frand(M_PI * 2.0);
GLfloat enter = frand(M_PI * 2.0);
frame->pos[3].y = BELLRAND(MI_HEIGHT(mi));
frame->pos[3].angle = (frand(2.0) - 1.0) * max_tilt;
+ /* Try to keep the images mostly inside the screen bounds */
+ frame->pos[3].x = MAX(0.5*w, MIN(MI_WIDTH(mi)-0.5*w, frame->pos[3].x));
+ frame->pos[3].y = MAX(0.5*h, MIN(MI_HEIGHT(mi)-0.5*h, frame->pos[3].y));
+
/* intermediate points */
frame->pos[1] = offset_pos(frame->pos[0], leave, d * (0.5 + frand(1.0)));
frame->pos[2] = offset_pos(frame->pos[3], enter, d * (0.5 + frand(1.0)));
free (frame->title);
frame->title = (filename ? strdup (filename) : 0);
-# if 0 /* xscreensaver-getimage returns paths relative to the image directory
- now, so leave the sub-directory part in.
- */
- if (frame->title) /* strip filename to part after last /. */
+ /* xscreensaver-getimage returns paths relative to the image directory
+ now, so leave the sub-directory part in. Unless it's an absolute path.
+ */
+ if (frame->title && frame->title[0] == '/')
{
+ /* strip filename to part after last /. */
char *s = strrchr (frame->title, '/');
if (s) strcpy (frame->title, s+1);
}
-# endif /* 0 */
if (debug_p)
fprintf (stderr, "%s: loaded %4d x %-4d %4d x %-4d \"%s\"\n",
if (wire) return;
if (ss->loading_sw == 0) /* only do this once */
- ss->loading_sw = texture_string_width (ss->texfont, text, &ss->loading_sh);
+ {
+ XCharStruct e;
+ texture_string_metrics (ss->texfont, text, &e, 0, 0);
+ ss->loading_sw = e.width;
+ ss->loading_sh = e.ascent + e.descent;
+ }
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
- gluOrtho2D(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi));
+ glOrtho(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi), -1, 1);
glTranslatef ((MI_WIDTH(mi) - ss->loading_sw) / 2,
(MI_HEIGHT(mi) - ss->loading_sh) / 2,
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluOrtho2D(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi));
+ glOrtho(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi), -1, 1);
+
+# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
+ {
+ GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
+ int o = (int) current_device_rotation();
+ if (o != 0 && o != 180 && o != -180)
+ glScalef (1/h, h, 1);
+ }
+# endif
glClear(GL_COLOR_BUFFER_BIT);
}
static void
hack_resources (Display *dpy)
{
-# ifndef HAVE_COCOA
+# ifndef HAVE_JWXYZ
char *res = "desktopGrabber";
char *val = get_string_resource (dpy, res, "DesktopGrabber");
char buf1[255];
value.addr = buf2;
value.size = strlen(buf2);
XrmPutResource (&db, buf1, "String", &value);
-# endif /* !HAVE_COCOA */
+# endif /* !HAVE_JWXYZ */
}
MI_CLEARWINDOW(mi);
}
- glDisable (GL_LIGHTING);
- glEnable (GL_DEPTH_TEST);
- glDisable (GL_CULL_FACE);
-
- if (! wire)
- {
- glShadeModel (GL_SMOOTH);
- glEnable (GL_LINE_SMOOTH);
- glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
ss->shadow = init_drop_shadow();
ss->texfont = load_texture_font (MI_DISPLAY(mi), "font");
{
glColor3f (0, 0, 0);
draw_drop_shadow(ss->shadow, -w1, -h1, z2, 2.0 * w1, h1 + h2, 20.0);
+ glDisable (GL_BLEND);
}
+ glDisable (GL_LIGHTING);
+ glEnable (GL_DEPTH_TEST);
+ glDisable (GL_CULL_FACE);
+
/* Draw the retro instant-film frame.
*/
if (polaroid_p)
{
if (! wire)
{
+ glShadeModel (GL_SMOOTH);
+ glEnable (GL_LINE_SMOOTH);
+ glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+
glColor3f (1, 1, 1);
glBegin (GL_QUADS);
glVertex3f (-w1, -h1, z2);
glEnd();
}
- glLineWidth (2.0);
+ glLineWidth (1.0);
glColor3f (0.5, 0.5, 0.5);
glBegin (GL_LINE_LOOP);
glVertex3f (-w1, -h1, z);
/* Draw a box around it.
*/
- glLineWidth (2.0);
+ if (! wire)
+ {
+ glShadeModel (GL_SMOOTH);
+ glEnable (GL_LINE_SMOOTH);
+ glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+ }
+ glLineWidth (1.0);
glColor3f (0.5, 0.5, 0.5);
glBegin (GL_LINE_LOOP);
glVertex3f (-w, -h, z);
*/
if (titles_p)
{
- int sw, sh;
- GLfloat scale = 0.6;
+ int sw, sh, ascent, descent;
+ GLfloat scale = 1;
const char *title = frame->title ? frame->title : "(untitled)";
+ XCharStruct e;
/* #### Highly approximate, but doing real clipping is harder... */
int max = 35;
if (strlen(title) > max)
title += strlen(title) - max;
- sw = texture_string_width (ss->texfont, title, &sh);
+ texture_string_metrics (ss->texfont, title, &e, &ascent, &descent);
+ sw = e.width;
+ sh = ascent + descent;
- glTranslatef (-sw*scale*0.5, -h - sh*scale, z);
+ /* Scale the text to match the pixel size of the photo */
+ scale *= w / 300.0;
+
+ /* Move to below photo */
+ glTranslatef (0, -h - sh * (polaroid_p ? 2.2 : 0.5), 0);
+ glTranslatef (-sw*scale/2, sh*scale/2, z);
glScalef (scale, scale, 1);
if (wire || !polaroid_p)
if (!wire)
{
glEnable (GL_TEXTURE_2D);
+ glEnable (GL_BLEND);
print_texture_string (ss->texfont, title);
- glDisable (GL_TEXTURE_2D);
}
else
{
{
GLfloat t;
+ glPushMatrix();
+ glTranslatef (MI_WIDTH(mi)/2, MI_HEIGHT(mi)/2, 0);
+ glRotatef(current_device_rotation(), 0, 0, 1);
+ glTranslatef (-MI_WIDTH(mi)/2, -MI_HEIGHT(mi)/2, 0);
+
/* Handle state transitions. */
switch (ss->mode)
{
- case IN:
+ case SHUFFLE:
if (--ss->mode_tick <= 0)
{
+ ss->nframe = (ss->nframe+1) % (MI_COUNT(mi)+1);
+
ss->mode = NORMAL;
ss->last_time = time((time_t *) 0);
}
ss->mode_tick = fade_ticks / speed;
}
break;
- case SHUFFLE:
- if (--ss->mode_tick <= 0)
- {
- ss->nframe = (ss->nframe+1) % (MI_COUNT(mi)+1);
-
- ss->mode = NORMAL;
- ss->last_time = time((time_t *) 0);
- }
- break;
default:
abort();
}
switch (ss->mode)
{
- case IN:
- s *= t;
- break;
- case NORMAL:
- case LOADING:
- t = 1.0;
- break;
case SHUFFLE:
if (i == MI_COUNT(mi))
{
s *= 1.0 - t;
}
break;
+ case NORMAL:
+ case LOADING:
+ t = 1.0;
+ break;
default:
abort();
}
draw_image(mi, j, t, s, z);
}
}
+ glPopMatrix();
}
if (mi->fps_p) do_fps (mi);