Add basic toolkit infrastructure

This commit is contained in:
Matthew Allum 2005-04-03 16:13:08 +00:00
parent a4ce71bb79
commit 668890821f
17 changed files with 860 additions and 534 deletions

View File

@ -1,3 +1,30 @@
2005-04-03 mallum,,, <mallum@openedhand.com>
* Makefile:
* cltr-core.c:
* cltr-core.h:
* cltr-events.c:
* cltr-events.h:
* cltr-photo-grid.c: (cltr_photo_grid_handle_xkeyevent),
(cltr_photo_grid_handle_xevent), (cltr_photo_grid_cell_new),
(cltr_photo_grid_append_cell), (ctrl_photo_grid_cell_to_coords),
(ctrl_photo_grid_get_zoomed_coords), (cell_is_offscreen),
(cltr_photo_grid_idle_cb), (cltr_photo_grid_navigate),
(cltr_photo_grid_activate_cell), (cltr_photo_grid_populate),
(cltr_photo_grid_paint), (cltr_photo_grid_show),
(cltr_photo_grid_new):
* cltr-photo-grid.h:
* cltr-private.h:
* cltr-texture.c:
* cltr-texture.h:
* cltr-widget.c:
* cltr-widget.h:
* cltr-window.c:
* cltr-window.h:
* cltr.c:
* cltr.h:
Add very basic initial toolkit infrastructure
2005-03-31 mallum,,, <mallum@openedhand.com>
* cltr-photo-grid.c: (cltr_photo_grid_append_cell),

View File

@ -4,12 +4,30 @@ CFLAGS=`pkg-config --cflags pangoft2 pango glib-2.0 gthread-2.0`
.c.o:
$(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
OBJS=cltr.o pixbuf.o util.o fonts.o cltr-photo-grid.o cltr-texture.o
OBJS=cltr.o pixbuf.o util.o fonts.o \
cltr-core.o \
cltr-texture.o \
cltr-widget.o \
cltr-events.o \
cltr-window.o \
cltr-photo-grid.o
# cltr-photo-grid.o
clutter: $(OBJS)
$(CC) -g -Wall -o $@ $(OBJS) $(LIBS)
$(OBJS): pixbuf.h util.h fonts.h cltr.h cltr-photo-grid.h cltr-texture.h
$(OBJS): pixbuf.h util.h fonts.h \
cltr.h \
cltr-private.h \
cltr-events.h \
cltr-texture.h \
cltr-widget.h \
cltr-window.h \
cltr-photo-grid.h
#cltr-photo-grid.h
clean:
rm -fr *.o clutter test

44
cltr-core.c Normal file
View File

@ -0,0 +1,44 @@
#include "cltr-core.h"
#include "cltr-private.h"
int
cltr_init(int *argc, char ***argv)
{
int gl_attributes[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
0
};
XVisualInfo *vinfo;
g_thread_init (NULL);
// XInitThreads ();
if ((CltrCntx.xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
{
return 0;
}
CltrCntx.xscreen = DefaultScreen(CltrCntx.xdpy);
CltrCntx.xwin_root = RootWindow(CltrCntx.xdpy, CltrCntx.xscreen);
if ((vinfo = glXChooseVisual(CltrCntx.xdpy,
CltrCntx.xscreen,
gl_attributes)) == NULL)
{
fprintf(stderr, "Unable to find visual\n");
return 0;
}
CltrCntx.gl_context = glXCreateContext(CltrCntx.xdpy, vinfo, 0, True);
cltr_events_init();
return 1;
}

9
cltr-core.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _HAVE_CLTR_CORE_H
#define _HAVE_CLTR_CORE_H
#include "cltr.h"
int
cltr_init(int *argc, char ***argv);
#endif

176
cltr-events.c Normal file
View File

@ -0,0 +1,176 @@
#include <X11/keysym.h>
#include "cltr-events.h"
#include "cltr-private.h"
typedef void (*CltrXEventFunc) (XEvent *xev, gpointer user_data);
typedef struct
{
GSource source;
Display *display;
GPollFD event_poll_fd;
}
CltrXEventSource;
static gboolean
x_event_prepare (GSource *source,
gint *timeout)
{
Display *display = ((CltrXEventSource*)source)->display;
*timeout = -1;
return XPending (display);
}
static gboolean
x_event_check (GSource *source)
{
CltrXEventSource *display_source = (CltrXEventSource*)source;
gboolean retval;
if (display_source->event_poll_fd.revents & G_IO_IN)
retval = XPending (display_source->display);
else
retval = FALSE;
return retval;
}
static gboolean
x_event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
Display *display = ((CltrXEventSource*)source)->display;
CltrXEventFunc event_func = (CltrXEventFunc) callback;
XEvent xev;
if (XPending (display))
{
XNextEvent (display, &xev);
if (event_func)
(*event_func) (&xev, user_data);
}
return TRUE;
}
static const GSourceFuncs x_event_funcs = {
x_event_prepare,
x_event_check,
x_event_dispatch,
NULL
};
void
cltr_dispatch_expose(XExposeEvent *xexpev)
{
// cltr_photo_grid_redraw(Grid);
}
void
cltr_dispatch_x_event (XEvent *xevent,
gpointer data)
{
/* Should actually forward on to focussed widget */
ClutterMainContext *ctx = CLTR_CONTEXT();
cltr_widget_handle_xevent(ctx->window, xevent);
#if 0
switch (xevent->type)
{
case MapNotify:
CLTR_DBG("Map Notify Event");
break;
case Expose:
CLTR_DBG("Expose"); /* TODO COMPRESS */
cltr_dispatch_expose(&xevent->xexpose);
break;
case KeyPress:
CLTR_DBG("KeyPress");
cltr_dispatch_keypress(&xevent->xkey);
break;
}
#endif
}
void
cltr_events_init()
{
GMainContext *gmain_context;
int connection_number;
GSource *source;
CltrXEventSource *display_source;
ClutterMainContext *ctx = CLTR_CONTEXT();
/* g_main loop stuff */
gmain_context = g_main_context_default ();
g_main_context_ref (gmain_context);
connection_number = ConnectionNumber (CltrCntx.xdpy);
source = g_source_new ((GSourceFuncs *)&x_event_funcs,
sizeof (CltrXEventSource));
display_source = (CltrXEventSource *)source;
display_source->event_poll_fd.fd = connection_number;
display_source->event_poll_fd.events = G_IO_IN;
display_source->display = CltrCntx.xdpy;
g_source_add_poll (source, &display_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE);
g_source_set_callback (source,
(GSourceFunc) cltr_dispatch_x_event,
NULL /* no userdata */, NULL);
g_source_attach (source, gmain_context);
g_source_unref (source);
ctx->internal_event_q = g_queue_new();
}
void
cltr_main_loop()
{
ClutterMainContext *ctx = CLTR_CONTEXT();
/*
GMainLoop *loop;
loop = g_main_loop_new (g_main_context_default (), FALSE);
g_main_loop_run (loop);
*/
while (TRUE)
{
if (!g_queue_is_empty (ctx->internal_event_q))
{
CltrWidget *widget = NULL;
CltrWindow *win = CLTR_WINDOW(ctx->window);
while ((widget = g_queue_pop_head(ctx->internal_event_q)) != NULL)
{
cltr_widget_paint(widget);
}
/* Swap Buffers */
glXSwapBuffers(ctx->xdpy, cltr_window_xwin(win));
}
/* while (g_main_context_pending(g_main_context_default ())) */
g_main_context_iteration (g_main_context_default (), TRUE);
}
}

18
cltr-events.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _HAVE_CLTR_EVENT_H
#define _HAVE_CLTR_EVENT_H
#include "cltr.h"
void
cltr_main_loop();
void
cltr_dispatch_x_event (XEvent *xevent,
gpointer data);
void
cltr_events_init();
#endif

View File

@ -1,18 +1,146 @@
#include "cltr-photo-grid.h"
#include "cltr-private.h"
/*
TODO
- image cache !!
- change idle_cb to timeouts, reduce tearing + inc interactivity on
image load
- Split events into seperate file ( break up ctrl.c )
- offset zoom a little to give border around picture grid
- figure out highlighting selected cell
- tape on pictures ?
- tidy this code here + document !
- fix threads, lower priority ?
*/
#define ANIM_FPS 60
#define FPS_TO_TIMEOUT(t) (1000/(t))
struct CltrPhotoGridCell
{
Pixbuf *pixb;
float angle;
CltrTexture *texture;
gint anim_step;
CltrPhotoGridCellState state;
};
struct CltrPhotoGrid
{
CltrWidget widget;
gchar *img_path;
int n_rows;
int n_cols;
int row_offset; /* for scrolling */
int cell_width;
int cell_height;
GList *cells_tail;
GList *cell_active;
/* animation / zoom etc stuff */
int anim_n_steps, anim_step;
float zoom_min, zoom_max, zoom_step;
float view_min_x, view_max_x, view_min_y, view_max_y;
float scroll_dist;
CltrPhotoGridState state;
int scroll_state, scroll_step; /* urg */
};
static void
cltr_photo_grid_paint(CltrWidget *widget);
static gboolean
cltr_photo_grid_handle_xevent (CltrWidget *widget, XEvent *xev);
static void
cltr_photo_grid_show(CltrWidget *widget);
/* this likely shouldn'y go here */
static GMutex *Mutex_GRID = NULL;
ClutterPhotoGridCell*
cltr_photo_grid_cell_new(ClutterPhotoGrid *grid,
Pixbuf *pixb,
const gchar *filename)
static void
cltr_photo_grid_handle_xkeyevent(CltrPhotoGrid *grid, XKeyEvent *xkeyev)
{
ClutterPhotoGridCell *cell = NULL;
int maxw = grid->width, maxh = grid->height;
KeySym kc;
kc = XKeycodeToKeysym(xkeyev->display, xkeyev->keycode, 0);
switch (kc)
{
case XK_Left:
case XK_KP_Left:
cltr_photo_grid_navigate(grid, CLTR_WEST);
break;
case XK_Up:
case XK_KP_Up:
cltr_photo_grid_navigate(grid, CLTR_NORTH);
break;
case XK_Right:
case XK_KP_Right:
cltr_photo_grid_navigate(grid, CLTR_EAST);
break;
case XK_Down:
case XK_KP_Down:
cltr_photo_grid_navigate(grid, CLTR_SOUTH);
break;
case XK_Return:
cltr_photo_grid_activate_cell(grid);
break;
default:
CLTR_DBG("unhandled keysym");
}
}
static gboolean
cltr_photo_grid_handle_xevent (CltrWidget *widget, XEvent *xev)
{
CltrPhotoGrid* grid = CLTR_PHOTO_GRID(widget);
switch (xev->type)
{
case KeyPress:
CLTR_DBG("KeyPress");
cltr_photo_grid_handle_xkeyevent(grid, &xev->xkey);
break;
}
return TRUE;
}
CltrPhotoGridCell*
cltr_photo_grid_cell_new(CltrPhotoGrid *grid,
Pixbuf *pixb,
const gchar *filename)
{
CltrPhotoGridCell *cell = NULL;
int maxw = grid->widget.width, maxh = grid->widget.height;
int neww = 0, newh = 0;
cell = g_malloc0(sizeof(ClutterPhotoGridCell));
cell = g_malloc0(sizeof(CltrPhotoGridCell));
if (pixb->width > pixb->height) /* landscape */
{
@ -49,8 +177,8 @@ cltr_photo_grid_cell_new(ClutterPhotoGrid *grid,
}
void
cltr_photo_grid_append_cell(ClutterPhotoGrid *grid,
ClutterPhotoGridCell *cell)
cltr_photo_grid_append_cell(CltrPhotoGrid *grid,
CltrPhotoGridCell *cell)
{
grid->cells_tail = g_list_append(grid->cells_tail, cell);
@ -59,7 +187,7 @@ cltr_photo_grid_append_cell(ClutterPhotoGrid *grid,
/* relative */
static void
ctrl_photo_grid_cell_to_coords(ClutterPhotoGrid *grid,
ctrl_photo_grid_cell_to_coords(CltrPhotoGrid *grid,
GList *cell,
int *x,
int *y)
@ -77,7 +205,7 @@ ctrl_photo_grid_cell_to_coords(ClutterPhotoGrid *grid,
}
static void
ctrl_photo_grid_get_zoomed_coords(ClutterPhotoGrid *grid,
ctrl_photo_grid_get_zoomed_coords(CltrPhotoGrid *grid,
int x,
int y,
float *tx,
@ -94,7 +222,7 @@ ctrl_photo_grid_get_zoomed_coords(ClutterPhotoGrid *grid,
}
static gboolean
cell_is_offscreen(ClutterPhotoGrid *grid,
cell_is_offscreen(CltrPhotoGrid *grid,
GList *cell,
CltrDirection *where)
{
@ -122,9 +250,9 @@ cell_is_offscreen(ClutterPhotoGrid *grid,
gboolean
cltr_photo_grid_idle_cb(gpointer data)
{
ClutterPhotoGrid *grid = (ClutterPhotoGrid *)data;
CltrPhotoGrid *grid = (CltrPhotoGrid *)data;
cltr_photo_grid_redraw(grid);
cltr_widget_queue_paint(CLTR_WIDGET(grid));
switch(grid->state)
{
@ -144,7 +272,7 @@ cltr_photo_grid_idle_cb(gpointer data)
void
cltr_photo_grid_navigate(ClutterPhotoGrid *grid,
cltr_photo_grid_navigate(CltrPhotoGrid *grid,
CltrDirection direction)
{
GList *cell_orig = grid->cell_active;
@ -198,7 +326,8 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid,
}
if (grid->state != CLTR_PHOTO_GRID_STATE_ZOOMED)
g_idle_add(cltr_photo_grid_idle_cb, grid);
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_photo_grid_idle_cb, grid);
}
if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED)
@ -215,7 +344,8 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid,
grid->anim_step = 0;
zoom = grid->zoom_max;
g_idle_add(cltr_photo_grid_idle_cb, grid);
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_photo_grid_idle_cb, grid);
}
ctrl_photo_grid_cell_to_coords(grid, grid->cell_active, &x, &y);
@ -226,19 +356,20 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid,
CLTR_DBG("x: %f, y: %f", grid->view_max_x , grid->view_max_y);
cltr_photo_grid_redraw(grid);
cltr_widget_queue_paint(CLTR_WIDGET(grid));
}
}
void /* bleh badly named */
cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid)
cltr_photo_grid_activate_cell(CltrPhotoGrid *grid)
{
if (grid->state == CLTR_PHOTO_GRID_STATE_BROWSE)
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOM_IN;
g_idle_add(cltr_photo_grid_idle_cb, grid);
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_photo_grid_idle_cb, grid);
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED)
{
@ -248,7 +379,8 @@ cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid)
grid->view_min_x = 0.0;
grid->view_min_y = 0.0; /*- (grid->row_offset * grid->cell_height);*/
g_idle_add(cltr_photo_grid_idle_cb, grid);
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_photo_grid_idle_cb, grid);
}
/* que a draw ? */
@ -258,7 +390,7 @@ cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid)
gpointer
cltr_photo_grid_populate(gpointer data)
{
ClutterPhotoGrid *grid = (ClutterPhotoGrid *)data;
CltrPhotoGrid *grid = (CltrPhotoGrid *)data;
GDir *dir;
GError *error;
const gchar *entry = NULL;
@ -296,7 +428,7 @@ cltr_photo_grid_populate(gpointer data)
if (pixb)
{
ClutterPhotoGridCell *cell;
CltrPhotoGridCell *cell;
gchar buf[24];
cell = cltr_photo_grid_cell_new(grid, pixb, entry);
@ -328,17 +460,22 @@ cltr_photo_grid_populate(gpointer data)
g_mutex_unlock(Mutex_GRID);
cltr_photo_grid_redraw(grid);
cltr_widget_queue_paint(CLTR_WIDGET(grid));
return NULL;
}
void
cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
static void
cltr_photo_grid_paint(CltrWidget *widget)
{
int x = 0, y = 0, rows = grid->n_rows+1, cols = 0, i =0;
int x = 0, y = 0, rows = 0, cols = 0, i =0;
GList *cell_item;
float zoom, trans_x, trans_y;
CltrWindow *win = CLTR_WINDOW(widget->parent);
CltrPhotoGrid *grid = (CltrPhotoGrid *)widget;
rows = grid->n_rows+1;
/* CLTR_MARK();*/
@ -349,11 +486,12 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
if (grid->cells_tail == NULL)
{
/* No pictures to paint yet */
CltrWindow *win = CLTR_WINDOW(grid->widget.parent);
glColor3f(0.6, 0.6, 0.62);
glRecti(0, 0, 640, 480);
glRecti(0, 0, widget->width, widget->height);
glPopMatrix();
glXSwapBuffers(CltrCntx.xdpy, grid->parent->xwin);
return;
}
@ -448,8 +586,6 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
trans_y = ((grid->view_max_y - grid->view_min_y + scroll_min_y_offset) * f) ;
y = 0;
printf("%f,%f, %f\n", grid->view_max_y, grid->view_min_y, scroll_min_y_offset);
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE)
@ -478,20 +614,20 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
grid->anim_step++;
if (grid->anim_step >= grid->anim_n_steps)
if (grid->anim_step >= (grid->anim_n_steps/4))
{
grid->state = CLTR_PHOTO_GRID_STATE_BROWSE;
grid->anim_step = 0;
zoom = grid->zoom_min;
}
else
{
float f = (float)grid->anim_step / grid->anim_n_steps;
float f = (float)grid->anim_step / (grid->anim_n_steps/4);
trans_y += (grid->scroll_dist * f);
if (grid->scroll_dist > 0) /* up */
{
y = (grid->row_offset-1) * grid->cell_height;
/* cell_item = g_list_nth(grid->cells_tail, grid->n_cols * (grid->row_offset+1));*/
}
else /* down */
{
@ -511,7 +647,7 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
x = 0;
while (cols--)
{
ClutterPhotoGridCell *cell = (ClutterPhotoGridCell *)cell_item->data;
CltrPhotoGridCell *cell = (CltrPhotoGridCell *)cell_item->data;
Pixbuf *pixb = NULL;
int x1, x2, y1, y2, thumb_w, thumb_h;
int ns_border, ew_border;
@ -607,9 +743,7 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
/* finally paint background */
glDisable(GL_TEXTURE_2D);
glColor3f(0.6, 0.6, 0.62);
glRecti(0, 0, 640, 480);
glXSwapBuffers(CltrCntx.xdpy, grid->parent->xwin);
glRecti(0, 0, widget->width, widget->height);
g_mutex_lock(Mutex_GRID);
@ -621,42 +755,50 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
}
ClutterPhotoGrid*
cltr_photo_grid_new(ClutterWindow *win,
static void
cltr_photo_grid_show(CltrWidget *widget)
{
CltrPhotoGrid* grid = CLTR_PHOTO_GRID(widget);
cltr_widget_queue_paint(widget);
}
CltrWidget*
cltr_photo_grid_new(int width,
int height,
int n_cols,
int n_rows,
const gchar *img_path)
{
ClutterPhotoGrid *grid = NULL;
CltrPhotoGrid *grid = NULL;
GThread *loader_thread;
grid = util_malloc0(sizeof(ClutterPhotoGrid));
grid = g_malloc0(sizeof(CltrPhotoGrid));
grid->widget.width = width;
grid->widget.height = height;
grid->widget.show = cltr_photo_grid_show;
grid->widget.paint = cltr_photo_grid_paint;
grid->widget.xevent_handler = cltr_photo_grid_handle_xevent;
grid->img_path = strdup(img_path);
grid->width = win->width;
grid->height = win->height;
grid->n_cols = n_cols;
grid->n_rows = n_rows;
grid->parent = win;
grid->cell_width = grid->width / n_cols;
grid->cell_height = grid->height / n_rows;
grid->cell_width = grid->widget.width / n_cols;
grid->cell_height = grid->widget.height / n_rows;
grid->state = CLTR_PHOTO_GRID_STATE_LOADING;
grid->anim_n_steps = 40; /* value needs to be calced dep on rows */
grid->anim_n_steps = 20; /* value needs to be calced dep on rows */
grid->anim_step = 0;
/*
grid->zoom_step = 0.05;
grid->zoom = 1.0;
*/
grid->zoom_min = 1.0;
grid->view_min_x = (grid->width - (grid->zoom_min * grid->width))/2.0;
grid->view_min_x = (grid->widget.width - (grid->zoom_min * grid->widget.width))/2.0;
grid->view_min_y = 0.0;
/* Assmes cols == rows */
grid->zoom_max = /* 1.0 + */ (float) (n_rows * 1.0); // - 0.3;
@ -673,17 +815,8 @@ cltr_photo_grid_new(ClutterWindow *win,
TRUE,
NULL);
/*
ctrl_photo_grid_cell_to_coords(grid, grid->cell_active, &x, &y);
g_timeout_add(FPS_TO_TIMEOUT(20),
cltr_photo_grid_idle_cb, grid);
ctrl_photo_grid_get_zoomed_coords(grid, grid->zoom_max,
x, y,
&grid->view_max_x,
&grid->view_max_y);
*/
g_idle_add(cltr_photo_grid_idle_cb, grid);
return grid;
return CLTR_WIDGET(grid);
}

View File

@ -3,11 +3,13 @@
#include "cltr.h"
typedef struct ClutterPhotoGrid ClutterPhotoGrid;
typedef struct CltrPhotoGrid CltrPhotoGrid;
typedef struct ClutterPhotoGridCell ClutterPhotoGridCell;
typedef struct CltrPhotoGridCell CltrPhotoGridCell;
typedef enum ClutterPhotoGridState
#define CLTR_PHOTO_GRID(w) (CltrPhotoGrid*)(w)
typedef enum CltrPhotoGridState
{
CLTR_PHOTO_GRID_STATE_LOADING ,
CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE ,
@ -18,90 +20,44 @@ typedef enum ClutterPhotoGridState
CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE ,
CLTR_PHOTO_GRID_STATE_SCROLLED_MOVE ,
}
ClutterPhotoGridState;
CltrPhotoGridState;
typedef enum ClutterPhotoGridCellState
typedef enum CltrPhotoGridCellState
{
CLTR_PHOTO_GRID_CELL_STATE_APPEARING,
CLTR_PHOTO_GRID_CELL_STATE_STATIC,
}
ClutterPhotoGridCellState;
CltrPhotoGridCellState;
struct ClutterPhotoGridCell
{
Pixbuf *pixb;
float angle;
CltrTexture *texture;
gint anim_step;
ClutterPhotoGridCellState state;
};
struct ClutterPhotoGrid
{
/* XXX should be base widget stuff */
int x,y;
int width;
int height;
ClutterWindow *parent;
/* ****** */
gchar *img_path;
int n_rows;
int n_cols;
int row_offset; /* for scrolling */
int cell_width;
int cell_height;
GList *cells_tail;
GList *cell_active;
/* animation / zoom etc stuff */
int anim_n_steps, anim_step;
float zoom_min, zoom_max, zoom_step;
float view_min_x, view_max_x, view_min_y, view_max_y;
float scroll_dist;
ClutterPhotoGridState state;
int scroll_state, scroll_step; /* urg */
};
ClutterPhotoGridCell*
cltr_photo_grid_cell_new(ClutterPhotoGrid *grid,
CltrPhotoGridCell*
cltr_photo_grid_cell_new(CltrPhotoGrid *grid,
Pixbuf *pixb,
const gchar *filename);
void
cltr_photo_grid_append_cell(ClutterPhotoGrid *grid,
ClutterPhotoGridCell *cell);
cltr_photo_grid_append_cell(CltrPhotoGrid *grid,
CltrPhotoGridCell *cell);
void
cltr_photo_grid_navigate(ClutterPhotoGrid *grid,
cltr_photo_grid_navigate(CltrPhotoGrid *grid,
CltrDirection direction) ;
void /* bleh badly named */
cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid);
cltr_photo_grid_activate_cell(CltrPhotoGrid *grid);
gpointer
cltr_photo_grid_populate(gpointer data) ;
void
cltr_photo_grid_redraw(ClutterPhotoGrid *grid);
cltr_photo_grid_redraw(CltrPhotoGrid *grid);
ClutterPhotoGrid*
cltr_photo_grid_new(ClutterWindow *win,
CltrWidget*
cltr_photo_grid_new(int width,
int height,
int n_cols,
int n_rows,
const gchar *imgs_path);
const gchar *img_path);
#endif

75
cltr-private.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _HAVE_CLTR_PRIVATE_H
#define _HAVE_CLTR_PRIVATE_H
#include "cltr.h"
#define CLTR_WANT_DEBUG 1
#if (CLTR_WANT_DEBUG)
#define CLTR_DBG(x, a...) \
g_printerr ( __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
#define CLTR_GLERR() \
{ \
GLenum err = glGetError (); /* Roundtrip */ \
if (err != GL_NO_ERROR) \
{ \
g_printerr (__FILE__ ": GL Error: %x [at %s:%d]\n", \
err, __func__, __LINE__); \
} \
}
#else
#define CLTR_DBG(x, a...) do {} while (0)
#define CLTR_GLERR() do {} while (0)
#endif
#define CLTR_MARK() CLTR_DBG("mark")
typedef void (*WidgetPaintMethod) (CltrWidget *widget ) ;
typedef void (*WidgetShowMethod) (CltrWidget *widget ) ;
typedef void (*WidgetDestroyMethod) (CltrWidget *widget) ;
typedef gboolean (*WidgetXEventHandler) (CltrWidget *widget, XEvent *xev) ;
struct CltrWidget
{
int x,y,width,height;
CltrWidget *parent;
gboolean visible;
GList *children;
/* methods */
WidgetPaintMethod paint;
WidgetShowMethod show;
WidgetDestroyMethod destroy;
WidgetXEventHandler xevent_handler;
};
typedef struct ClutterMainContext ClutterMainContext;
struct ClutterMainContext
{
Display *xdpy;
Window xwin_root;
int xscreen;
GC xgc;
GLXContext gl_context;
CltrWidget *window;
GQueue *internal_event_q;
};
ClutterMainContext CltrCntx;
#define CLTR_CONTEXT() &CltrCntx
#endif

View File

@ -1,4 +1,5 @@
#include "cltr-texture.h"
#include "cltr-private.h"
/*
IDEAS or less memory

View File

@ -3,6 +3,24 @@
#include "cltr.h"
typedef struct CltrTexture CltrTexture;
struct CltrTexture
{
Pixbuf *pixb;
int width, height;
int n_x_tiles, n_y_tiles;
int *tile_x_position, *tile_x_size, *tile_x_waste;
int *tile_y_position, *tile_y_size, *tile_y_waste;
GLuint *tiles;
gint refcnt;
};
CltrTexture*
cltr_texture_new(Pixbuf *pixb);

82
cltr-widget.c Normal file
View File

@ -0,0 +1,82 @@
#include "cltr-widget.h"
#include "cltr-private.h"
CltrWidget*
cltr_widget_new(void)
{
CltrWidget *w = NULL;
w = g_malloc0(sizeof(CltrWidget));
return w;
}
void
cltr_widget_show(CltrWidget *widget)
{
if (widget->show)
{
widget->visible = TRUE;
widget->show(widget);
}
}
void
cltr_widget_show_all(CltrWidget *widget)
{
GList *widget_item = widget->children;;
if (widget_item)
{
do
{
CltrWidget *child = CLTR_WIDGET(widget_item->data);
cltr_widget_show(child);
}
while ((widget_item = g_list_next(widget_item)) != NULL);
}
cltr_widget_show(widget);
}
void
cltr_widget_add_child(CltrWidget *widget, CltrWidget *child, int x, int y)
{
widget->children = g_list_append(widget->children, child);
child->parent = widget;
child->x = x;
child->y = y;
}
void
cltr_widget_hide(CltrWidget *widget)
{
widget->visible = FALSE;
}
void
cltr_widget_paint(CltrWidget *widget)
{
if (widget->paint && widget->visible)
widget->paint(widget);
}
void
cltr_widget_queue_paint(CltrWidget *widget)
{
ClutterMainContext *ctx = CLTR_CONTEXT();
g_queue_push_head (ctx->internal_event_q, (gpointer)widget);
}
gboolean
cltr_widget_handle_xevent(CltrWidget *widget, XEvent *xev)
{
if (widget && widget->xevent_handler)
return widget->xevent_handler(widget, xev);
return FALSE;
}

36
cltr-widget.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _HAVE_CLTR_WIDGET_H
#define _HAVE_CLTR_WIDGET_H
typedef struct CltrWidget CltrWidget;
#include "cltr.h"
#define CLTR_WIDGET(w) ((CltrWidget*)(w))
CltrWidget*
cltr_widget_new(void);
void
cltr_widget_show(CltrWidget *widget);
void
cltr_widget_paint(CltrWidget *widget);
gboolean
cltr_widget_handle_xevent(CltrWidget *widget, XEvent *xev);
void
cltr_widget_show_all(CltrWidget *widget);
void
cltr_widget_queue_paint(CltrWidget *widget);
void
cltr_widget_add_child(CltrWidget *widget, CltrWidget *child, int x, int y);
#endif

101
cltr-window.c Normal file
View File

@ -0,0 +1,101 @@
#include "cltr-window.h"
#include "cltr-private.h"
static gboolean
cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev);
static void
cltr_window_show(CltrWidget *widget);
struct CltrWindow
{
CltrWidget widget;
Window xwin;
CltrWidget *focused_child;
};
CltrWidget*
cltr_window_new(int width, int height)
{
ClutterMainContext *ctx = CLTR_CONTEXT();
CltrWindow *win;
win = util_malloc0(sizeof(CltrWindow));
win->widget.width = width;
win->widget.height = height;
win->widget.show = cltr_window_show;
win->widget.xevent_handler = cltr_window_handle_xevent;
win->xwin = XCreateSimpleWindow(CltrCntx.xdpy,
CltrCntx.xwin_root,
0, 0,
width, height,
0, 0, WhitePixel(CltrCntx.xdpy,
CltrCntx.xscreen));
XSelectInput(CltrCntx.xdpy, win->xwin,
StructureNotifyMask|ExposureMask|
KeyPressMask|PropertyChangeMask);
glXMakeCurrent(CltrCntx.xdpy, win->xwin, CltrCntx.gl_context);
/* All likely better somewhere else */
/* view port */
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, width, height, 0, -1, 1); /* 2d */
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
ctx->window = CLTR_WIDGET(win);
return CLTR_WIDGET(win);
}
Window
cltr_window_xwin(CltrWindow *win)
{
return win->xwin;
}
static void
cltr_window_show(CltrWidget *widget)
{
ClutterMainContext *ctx = CLTR_CONTEXT();
CltrWindow *win = CLTR_WINDOW(widget);
/* XXX set focused call */
if (widget->children)
{
win->focused_child = g_list_nth_data(widget->children, 0);
}
XMapWindow(ctx->xdpy, win->xwin);
}
static gboolean
cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev)
{
CltrWindow *win = CLTR_WINDOW(widget);
/* XXX handle exposes here too */
if (xev->type == Expose)
{
;
}
/* XXX Very basic - assumes we are only interested in mouse clicks */
if (win->focused_child)
return cltr_widget_handle_xevent(win->focused_child, xev);
return FALSE;
}
/* window only */

23
cltr-window.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _HAVE_CLTR_WINDOW_H
#define _HAVE_CLTR_WINDOW_H
#include "cltr.h"
typedef struct CltrWindow CltrWindow;
#define CLTR_WINDOW(w) ((CltrWindow*)(w))
CltrWidget*
cltr_window_new(int width, int height);
Window
cltr_window_xwin(CltrWindow *win);
void
cltr_window_paint(CltrWidget *widget);
void
cltr_window_add_widget(CltrWindow *win, CltrWidget *widget, int x, int y);
#endif

318
cltr.c
View File

@ -1,308 +1,10 @@
#include "cltr.h"
#include <X11/keysym.h>
/* temp temp temp */
float Zoom = 1.0;
ClutterPhotoGrid *Grid = NULL;
/* ************* */
static gboolean
x_event_prepare (GSource *source,
gint *timeout)
{
Display *display = ((CltrXEventSource*)source)->display;
*timeout = -1;
return XPending (display);
}
static gboolean
x_event_check (GSource *source)
{
CltrXEventSource *display_source = (CltrXEventSource*)source;
gboolean retval;
if (display_source->event_poll_fd.revents & G_IO_IN)
retval = XPending (display_source->display);
else
retval = FALSE;
return retval;
}
static gboolean
x_event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
Display *display = ((CltrXEventSource*)source)->display;
CltrXEventFunc event_func = (CltrXEventFunc) callback;
XEvent xev;
if (XPending (display))
{
XNextEvent (display, &xev);
if (event_func)
(*event_func) (&xev, user_data);
}
return TRUE;
}
static const GSourceFuncs x_event_funcs = {
x_event_prepare,
x_event_check,
x_event_dispatch,
NULL
};
void
cltr_dispatch_expose(XExposeEvent *xexpev)
{
cltr_photo_grid_redraw(Grid);
}
void
cltr_dispatch_keypress(XKeyEvent *xkeyev)
{
KeySym kc;
kc = XKeycodeToKeysym(xkeyev->display, xkeyev->keycode, 0);
switch (kc)
{
case XK_Left:
case XK_KP_Left:
cltr_photo_grid_navigate(Grid, CLTR_WEST);
break;
case XK_Up:
case XK_KP_Up:
cltr_photo_grid_navigate(Grid, CLTR_NORTH);
break;
case XK_Right:
case XK_KP_Right:
cltr_photo_grid_navigate(Grid, CLTR_EAST);
break;
case XK_Down:
case XK_KP_Down:
cltr_photo_grid_navigate(Grid, CLTR_SOUTH);
break;
case XK_Return:
cltr_photo_grid_activate_cell(Grid);
break;
default:
CLTR_DBG("unhandled keysym");
}
}
static void
cltr_dispatch_x_event (XEvent *xevent,
gpointer data)
{
/* Should actually forward on to focussed widget */
switch (xevent->type)
{
case MapNotify:
CLTR_DBG("Map Notify Event");
break;
case Expose:
CLTR_DBG("Expose"); /* TODO COMPRESS */
cltr_dispatch_expose(&xevent->xexpose);
break;
case KeyPress:
CLTR_DBG("KeyPress");
cltr_dispatch_keypress(&xevent->xkey);
break;
}
}
int
cltr_init(int *argc, char ***argv)
{
int gl_attributes[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
0
};
XVisualInfo *vinfo;
GMainContext *gmain_context;
int connection_number;
GSource *source;
CltrXEventSource *display_source;
g_thread_init (NULL);
// XInitThreads ();
if ((CltrCntx.xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
{
return 0;
}
CltrCntx.xscreen = DefaultScreen(CltrCntx.xdpy);
CltrCntx.xwin_root = RootWindow(CltrCntx.xdpy, CltrCntx.xscreen);
if ((vinfo = glXChooseVisual(CltrCntx.xdpy,
CltrCntx.xscreen,
gl_attributes)) == NULL)
{
fprintf(stderr, "Unable to find visual\n");
return 0;
}
CltrCntx.gl_context = glXCreateContext(CltrCntx.xdpy, vinfo, 0, True);
/* g_main loop stuff */
gmain_context = g_main_context_default ();
g_main_context_ref (gmain_context);
connection_number = ConnectionNumber (CltrCntx.xdpy);
source = g_source_new ((GSourceFuncs *)&x_event_funcs,
sizeof (CltrXEventSource));
display_source = (CltrXEventSource *)source;
display_source->event_poll_fd.fd = connection_number;
display_source->event_poll_fd.events = G_IO_IN;
display_source->display = CltrCntx.xdpy;
g_source_add_poll (source, &display_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE);
g_source_set_callback (source,
(GSourceFunc) cltr_dispatch_x_event,
NULL /* no userdata */, NULL);
g_source_attach (source, gmain_context);
g_source_unref (source);
return 1;
}
ClutterWindow*
cltr_window_new(int width, int height)
{
ClutterWindow *win;
win = util_malloc0(sizeof(ClutterWindow));
win->width = width;
win->height = height;
win->xwin = XCreateSimpleWindow(CltrCntx.xdpy,
CltrCntx.xwin_root,
0, 0,
width, height,
0, 0, WhitePixel(CltrCntx.xdpy,
CltrCntx.xscreen));
XSelectInput(CltrCntx.xdpy, win->xwin,
StructureNotifyMask|ExposureMask|
KeyPressMask|PropertyChangeMask);
glXMakeCurrent(CltrCntx.xdpy, win->xwin, CltrCntx.gl_context);
/* All likely better somewhere else */
/* view port */
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, width, height, 0, -1, 1); /* 2d */
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glEnable (GL_TEXTURE_2D);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
return win;
}
void
cltr_main_loop()
{
GMainLoop *loop;
loop = g_main_loop_new (g_main_context_default (), FALSE);
CLTR_MARK();
g_main_loop_run (loop);
}
gboolean
test_idle_cb(gpointer data)
{
static float angle = 0.0;
glClear(GL_COLOR_BUFFER_BIT);
glClearColor( 0.6, 0.6, 0.62, 1.0);
glColor3f(0.0, 0.0, 0.0);
glTranslatef( 0.0, 0.0, 0.0);
/* get a copy of our untranformed matrix */
glPushMatrix();
/* Translate origin to rotation point */
glTranslatef( 320.0, 240.0, 0.0);
/* Rotate around Z axis */
glRotatef ( angle, 0.0, 0.0, 1.0);
/* Draw tranformed rect with origin at center */
glRecti(-50, -50, 50, 50);
/* Reset our un transformed matrix */
glPopMatrix();
glRecti(-50, -50, 50, 50);
angle += 0.1;
glXSwapBuffers(CltrCntx.xdpy, (Window)data);
return TRUE;
}
int
main(int argc, char **argv)
{
ClutterPhotoGrid *grid = NULL;
ClutterWindow *win = NULL;
/*
Pixbuf *p1, *p2, *p3;
CltrWidget *win = NULL, *grid = NULL;
p1 = pixbuf_new(2000,2000);
p2 = pixbuf_new(640,480);
p3 = pixbuf_scale_down(p1, 512, 512);
pixbuf_copy(p3, p2, 0,0, 1000, 1000,0,0);
exit(1);
*/
if (argc < 2)
{
g_printerr("usage: '%s' <path to not too heavily populated image dir>\n"
@ -314,23 +16,11 @@ main(int argc, char **argv)
win = cltr_window_new(640, 480);
grid = cltr_photo_grid_new(win, 3, 3, argv[1]);
grid = cltr_photo_grid_new(640, 480, 3, 3, argv[1]);
Grid = grid; /* laaaaaazy globals */
cltr_widget_add_child(win, grid, 0, 0);
// cltr_photo_grid_redraw(grid);
// g_idle_add(idle_cb, grid);
// g_timeout_add (10, idle_cb, grid);
// g_idle_add(test_idle_cb, (gpointer)win->xwin);
XFlush(CltrCntx.xdpy);
XMapWindow(CltrCntx.xdpy, win->xwin);
XFlush(CltrCntx.xdpy);
cltr_widget_show_all(win);
cltr_main_loop();

93
cltr.h
View File

@ -8,6 +8,7 @@
#include <math.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <GL/glx.h>
#include <GL/gl.h>
@ -17,53 +18,6 @@
#include "pixbuf.h"
#include "fonts.h"
#define CLTR_WANT_DEBUG 1
#if (CLTR_WANT_DEBUG)
#define CLTR_DBG(x, a...) \
g_printerr ( __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
#define CLTR_GLERR() \
{ \
GLenum err = glGetError (); /* Roundtrip */ \
if (err != GL_NO_ERROR) \
{ \
g_printerr (__FILE__ ": GL Error: %x [at %s:%d]\n", \
err, __func__, __LINE__); \
} \
}
#else
#define CLTR_DBG(x, a...) do {} while (0)
#define CLTR_GLERR() do {} while (0)
#endif
#define CLTR_MARK() CLTR_DBG("mark")
typedef struct CltrTexturePool CltrTexturePool;
struct CltrTexturePool
{
GList *texture_items;
gint n_texture_items;
GLuint *gl_textures;
};
typedef struct ClutterMainContext ClutterMainContext;
struct ClutterMainContext
{
Display *xdpy;
Window xwin_root;
int xscreen;
GC xgc;
GLXContext gl_context;
CltrTexturePool texture_pool;
};
typedef enum CltrDirection
{
CLTR_NORTH,
@ -73,51 +27,16 @@ typedef enum CltrDirection
}
CltrDirection;
typedef struct ClutterWindow ClutterWindow;
struct ClutterWindow
{
Window xwin;
int width;
int height;
};
ClutterMainContext CltrCntx;
/* Event Loop Integration */
typedef void (*CltrXEventFunc) (XEvent *xev, gpointer user_data);
typedef struct
{
GSource source;
Display *display;
GPollFD event_poll_fd;
}
CltrXEventSource;
/* texture stuff */
typedef struct CltrTexture CltrTexture;
struct CltrTexture
{
Pixbuf *pixb;
int width, height;
int n_x_tiles, n_y_tiles;
int *tile_x_position, *tile_x_size, *tile_x_waste;
int *tile_y_position, *tile_y_size, *tile_y_waste;
GLuint *tiles;
gint refcnt;
};
/* ******************* */
#include "cltr-core.h"
#include "cltr-texture.h"
#include "cltr-events.h"
#include "cltr-widget.h"
#include "cltr-window.h"
#include "cltr-photo-grid.h"
#endif