summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/artwork/Makefile.am8
-rw-r--r--plugins/artwork/albumartorg.c54
-rw-r--r--plugins/artwork/albumartorg.h25
-rw-r--r--plugins/artwork/artwork.c233
-rw-r--r--plugins/artwork/artwork.h24
-rw-r--r--plugins/artwork/lastfm.c40
-rw-r--r--plugins/artwork/lastfm.h25
-rw-r--r--plugins/gtkui/Makefile.am3
-rw-r--r--plugins/gtkui/coverart.c70
-rw-r--r--plugins/gtkui/coverart.h36
-rw-r--r--plugins/gtkui/gtkui.c15
-rw-r--r--plugins/gtkui/mainplaylist.c14
12 files changed, 540 insertions, 7 deletions
diff --git a/plugins/artwork/Makefile.am b/plugins/artwork/Makefile.am
new file mode 100644
index 00000000..de137844
--- /dev/null
+++ b/plugins/artwork/Makefile.am
@@ -0,0 +1,8 @@
+artworkdir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = artwork.la
+artwork_la_SOURCES = artwork.h albumartorg.c artwork.c lastfm.c
+
+artwork_la_LDFLAGS = -module
+
+artwork_la_LIBADD = $(LDADD) $(ARTWORK_DEPS_LIBS) $(CURL_LIBS)
+AM_CFLAGS = -std=c99 $(ARTWORK_DEPS_CFLAGS)
diff --git a/plugins/artwork/albumartorg.c b/plugins/artwork/albumartorg.c
new file mode 100644
index 00000000..06247f74
--- /dev/null
+++ b/plugins/artwork/albumartorg.c
@@ -0,0 +1,54 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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.
+*/
+#include <stdlib.h>
+#include <curl/curl.h>
+#include <string.h>
+#include "artwork.h"
+
+int
+fetch_from_albumart_org (const char *artist, const char *album, const char *dest)
+{
+ char url [1024];
+ char *artist_url = curl_easy_escape (NULL, artist, 0);
+ char *album_url = curl_easy_escape (NULL, album, 0);
+ snprintf (url, sizeof (url), "http://www.albumart.org/index.php?srchkey=%s+%s&itempage=1&newsearch=1&searchindex=Music", artist_url, album_url);
+ curl_free (artist_url);
+ curl_free (album_url);
+
+ char *response = fetch (url);
+// printf ("%s\n", response);
+ char *img = strstr (response, "http://ecx.images-amazon.com/images/I/");
+ if (!img)
+ {
+ free (response);
+ return 0;
+ }
+ char *end = strstr (img, "._SL160_");
+ if (!end)
+ {
+ free (response);
+ return 0;
+ }
+ strcpy (end, ".jpg");
+
+ int res = fetch_to_file (img, dest);
+ free (response);
+ return res;
+}
+
diff --git a/plugins/artwork/albumartorg.h b/plugins/artwork/albumartorg.h
new file mode 100644
index 00000000..4d1d494a
--- /dev/null
+++ b/plugins/artwork/albumartorg.h
@@ -0,0 +1,25 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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 __ALBUMARTORG_H
+#define __ALBUMARTORG_H
+
+int
+fetch_from_albumart_org (const char *artist, const char *album, const char *dest);
+
+#endif
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
new file mode 100644
index 00000000..a136d29e
--- /dev/null
+++ b/plugins/artwork/artwork.c
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <errno.h>
+#include <dirent.h>
+#include "../../deadbeef.h"
+#include "artwork.h"
+#include "lastfm.h"
+#include "albumartorg.h"
+
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(...)
+
+static DB_artwork_plugin_t plugin;
+DB_functions_t *deadbeef;
+
+int
+fetch_to_stream (const char *url, FILE *stream)
+{
+ CURL *curl = curl_easy_init();
+ curl_easy_setopt (curl, CURLOPT_URL, url);
+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, stream);
+ curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
+ CURLcode ret = curl_easy_perform (curl);
+ curl_easy_cleanup (curl);
+ return ret;
+}
+
+int
+fetch_to_file (const char *url, const char *filename)
+{
+ /**
+ * Downloading files directly to its locations can cause
+ * cachehits of semi-downloaded files. That's why I use
+ * temporary files
+ */
+ char temp [1024];
+ int ret;
+ snprintf (temp, sizeof (temp), "%s.part", filename);
+
+ FILE *stream = fopen (temp, "wb");
+ if (!stream)
+ {
+ fprintf (stderr, "Could not open %s for writing\n", temp);
+ return 0;
+ }
+ ret = fetch_to_stream (url, stream);
+ if (ret != 0)
+ printf ("Failed to fetch %s\n", url);
+ fclose (stream);
+ if (0 == ret)
+ {
+ ret = (0 == rename (temp, filename));
+ if (!ret)
+ trace ("Could not move %s to %s: %d\n", temp, filename, errno);
+ }
+ return ret;
+}
+
+char*
+fetch (const char *url)
+{
+ char *data;
+ size_t size;
+ FILE *stream = open_memstream (&data, &size);
+ fetch_to_stream (url, stream);
+ fclose (stream);
+ return data;
+}
+
+static int
+check_dir (const char *dir, mode_t mode)
+{
+ char *tmp = strdup (dir);
+ char *slash = tmp;
+ struct stat stat_buf;
+ do
+ {
+ slash = strstr (slash+1, "/");
+ if (slash)
+ *slash = 0;
+// trace ("Checking %s\n", tmp);
+ if (-1 == stat (tmp, &stat_buf))
+ {
+ if (0 != mkdir (tmp, mode))
+ {
+ trace ("Failed to create %s (%d)\n", tmp, errno);
+ free (tmp);
+ return 0;
+ }
+ }
+ if (slash)
+ *slash = '/';
+ }
+ while (slash);
+ free (tmp);
+ return 1;
+}
+
+typedef struct
+{
+ const char *artist;
+ const char *album;
+ artwork_callback callback;
+} fetcher_thread_param_t;
+
+static void
+fetcher_thread (fetcher_thread_param_t *param)
+{
+ char path [1024];
+
+ snprintf (path, sizeof (path), "%s/artcache/%s", deadbeef->get_config_dir (), param->artist);
+ if (!check_dir (path, 0755))
+ goto finalize;
+
+ snprintf (path, sizeof (path), "%s/artcache/%s/%s.jpg", deadbeef->get_config_dir (), param->artist, param->album);
+
+ if (!fetch_from_lastfm (param->artist, param->album, path))
+ if (!fetch_from_albumart_org (param->artist, param->album, path))
+ goto finalize;
+
+ if (param->callback)
+ param->callback (param->artist, param->album);
+
+finalize:
+ free (param);
+ return;
+}
+
+static int
+filter_jpg (const struct dirent *f)
+{
+ const char *ext = strrchr (f->d_name, '.');
+ if (!ext)
+ return 0;
+ if (0 == strcasecmp (ext, ".jpg") ||
+ 0 == strcasecmp (ext, ".jpeg"))
+ return 1;
+ return 0;
+}
+
+char*
+get_album_art (DB_playItem_t *track, artwork_callback callback)
+{
+ char path [1024];
+ struct dirent **files;
+ int files_count;
+
+ const char *album = deadbeef->pl_find_meta (track, "album");
+ const char *artist = deadbeef->pl_find_meta (track, "artist");
+
+ /* Searching in track diectory */
+ strncpy (path, track->fname, sizeof (path));
+ *(strrchr (path, '/')) = 0; //Supposing at least one slash exist
+// trace ("Scanning: %s\n", path);
+ files_count = scandir (path, &files, filter_jpg, alphasort);
+
+/* if (files_count < 0)
+ trace ("Failed to scan dir");
+ if (files_count == 0)
+ trace ("No jpg's found in directoy");*/
+ if (files_count > 0)
+ {
+ strcat (path, "/");
+ strcat (path, files[0]->d_name);
+ char *res = strdup (path);
+ trace ("Found: %s\n", res);
+ int i;
+ for (i = 0; i < files_count; i++)
+ free (files [i]);
+ return res;
+ }
+
+ /* Searching in cache */
+ if (!artist || !*artist || !album || !*album)
+ {
+ //give up
+ return PREFIX "/share/deadbeef/pixmaps/blank_cd.jpg";
+ }
+
+ snprintf (path, sizeof (path), "%s/artcache/%s/%s.jpg", deadbeef->get_config_dir (), artist, album);
+
+ struct stat stat_buf;
+ if (0 == stat (path, &stat_buf))
+ {
+ char *res = strdup (path);
+// printf ("Found in cache: %s\n", res);
+ return res;
+ }
+
+ /* Downloading from internet */
+ trace ("Downloading: %s %s\n", artist, album);
+ fetcher_thread_param_t *param = malloc (sizeof (fetcher_thread_param_t));
+ param->artist = artist;
+ param->album = album;
+ param->callback = callback;
+ deadbeef->thread_start ((void (*)(void *))fetcher_thread, param);
+ return PREFIX "/share/deadbeef/pixmaps/blank_cd.jpg";
+}
+
+DB_plugin_t *
+artwork_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
+
+static int
+artwork_plugin_start (void)
+{
+}
+
+static int
+artwork_plugin_stop (void)
+{
+}
+
+// define plugin interface
+static DB_artwork_plugin_t plugin = {
+ .plugin.plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .plugin.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .plugin.plugin.type = DB_PLUGIN_MISC,
+ .plugin.plugin.id = "cover_loader",
+ .plugin.plugin.name = "Album Artwork",
+ .plugin.plugin.descr = "Loads album artwork either from local directories or from internet",
+ .plugin.plugin.author = "Viktor Semykin",
+ .plugin.plugin.email = "thesame.ml@gmail.com",
+ .plugin.plugin.website = "http://deadbeef.sf.net",
+ .plugin.plugin.start = artwork_plugin_start,
+ .plugin.plugin.stop = artwork_plugin_stop,
+ .get_album_art = get_album_art,
+};
diff --git a/plugins/artwork/artwork.h b/plugins/artwork/artwork.h
new file mode 100644
index 00000000..816ca349
--- /dev/null
+++ b/plugins/artwork/artwork.h
@@ -0,0 +1,24 @@
+#ifndef __ARTWORK_H
+#define __ARTWORK_H
+
+#include "../../deadbeef.h"
+
+typedef void (*artwork_callback) (const char *artist, const char *album);
+
+char*
+fetch (const char *url);
+
+int
+fetch_to_file (const char *url, const char *filename);
+
+int
+fetch_to_stream (const char *url, FILE *stream);
+
+typedef struct {
+ DB_misc_t plugin;
+ // returns filename of cached image, or NULL
+ char* (*get_album_art) (DB_playItem_t *track, artwork_callback callback);
+} DB_artwork_plugin_t;
+
+#endif /*__ARTWORK_H*/
+
diff --git a/plugins/artwork/lastfm.c b/plugins/artwork/lastfm.c
new file mode 100644
index 00000000..e64af10b
--- /dev/null
+++ b/plugins/artwork/lastfm.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <string.h>
+#include <curl/curl.h>
+#include <stdlib.h>
+
+#include "artwork.h"
+
+#define BASE_URL "http://ws.audioscrobbler.com/2.0/"
+#define API_KEY "b25b959554ed76058ac220b7b2e0a026"
+
+int
+fetch_from_lastfm (const char *artist, const char *album, const char *dest)
+{
+ char url [1024];
+ char *artist_url = curl_easy_escape (NULL, artist, 0);
+ char *album_url = curl_easy_escape (NULL, album, 0);
+ snprintf (url, sizeof (url), BASE_URL "?method=album.getinfo&api_key=" API_KEY "&artist=%s&album=%s", artist_url, album_url );
+ curl_free (artist_url);
+ curl_free (album_url);
+
+ char *response = fetch (url);
+// printf ("%s\n", response);
+ char *img = strstr (response, "<image size=\"extralarge\">");
+ if (!img)
+ {
+ free (response);
+ return 0;
+ }
+ img += 25;
+ char *end = strstr (img, "</image>");
+ if (!end || (end == img))
+ {
+ free (response);
+ return 0;
+ }
+ *end = 0;
+ int res = fetch_to_file (img, dest);
+ free (response);
+ return res;
+}
diff --git a/plugins/artwork/lastfm.h b/plugins/artwork/lastfm.h
new file mode 100644
index 00000000..09ec817c
--- /dev/null
+++ b/plugins/artwork/lastfm.h
@@ -0,0 +1,25 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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 __LASTFM_H
+#define __LASTFM_H
+
+int
+fetch_from_lastfm (const char *artist, const char *album, const char *dest);
+
+#endif
diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am
index eeeabce9..ed8d1c24 100644
--- a/plugins/gtkui/Makefile.am
+++ b/plugins/gtkui/Makefile.am
@@ -13,7 +13,8 @@ gtkui_la_SOURCES = gtkui.c gtkui.h\
parser.c parser.h\
ddbtabstrip.c ddbtabstrip.h\
ddbvolumebar.c ddbvolumebar.h\
- trkproperties.c trkproperties.h
+ trkproperties.c trkproperties.h\
+ coverart.c coverart.h
gtkui_la_LDFLAGS = -module
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
new file mode 100644
index 00000000..7d042e5f
--- /dev/null
+++ b/plugins/gtkui/coverart.c
@@ -0,0 +1,70 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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.
+*/
+#include <gtk/gtk.h>
+#include "coverart.h"
+#include "../artwork/artwork.h"
+
+extern DB_artwork_plugin_t *coverart_plugin;
+
+void
+cover_avail_callback (const char *artist, const char *album) {
+}
+
+static GdkPixbuf *
+get_pixbuf (const char *fname, int width) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (fname, NULL);
+ if (!pixbuf) {
+ return NULL;
+ }
+ int w, h;
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+ if (w == width) {
+ return pixbuf;
+ }
+ int height;
+ if (w > h) {
+ height = width * h / w;
+ }
+ else if (h > w) {
+ height = width;
+ width = height * w / h;
+ }
+ else {
+ height = width;
+ }
+ printf ("width=%d/%d, height=%d/%d\n", width, w, height, h);
+
+ GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+ return scaled;
+}
+
+GdkPixbuf *
+get_cover_art (DB_playItem_t *it, int width) {
+ if (!coverart_plugin) {
+ return NULL;
+ }
+ const char *fname = coverart_plugin->get_album_art (it, cover_avail_callback);
+ if (fname) {
+ printf ("loading %s\n", fname);
+ return get_pixbuf (fname, width);
+ }
+ return NULL;
+}
diff --git a/plugins/gtkui/coverart.h b/plugins/gtkui/coverart.h
new file mode 100644
index 00000000..0f1238ea
--- /dev/null
+++ b/plugins/gtkui/coverart.h
@@ -0,0 +1,36 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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 __COVERART_H
+#define __COVERART_H
+
+#include <gtk/gtk.h>
+#include "../../deadbeef.h"
+
+// this function puts request for cover art into queue, or returns default image
+// of specific size
+//
+// if the image is not available immediately -- callback will be called later,
+// which will redraw all tracks matching the query
+//
+// if cover art loader plugin is not available -- NULL will be returned
+GdkPixbuf *
+get_cover_art (DB_playItem_t *it, int width);
+
+#endif
+
diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c
index acde4de8..316a237f 100644
--- a/plugins/gtkui/gtkui.c
+++ b/plugins/gtkui/gtkui.c
@@ -39,6 +39,7 @@
#include "parser.h"
#include "drawing.h"
#include "trkproperties.h"
+#include "../artwork/artwork.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -48,6 +49,9 @@ DB_functions_t *deadbeef;
static intptr_t gtk_tid;
+// cover art loading plugin
+DB_artwork_plugin_t *coverart_plugin = NULL;
+
// main widgets
GtkWidget *mainwin;
GtkWidget *searchwin;
@@ -825,6 +829,17 @@ gtkui_thread (void *ctx) {
static int
gtkui_start (void) {
+ // find coverart plugin
+ DB_plugin_t **plugins = deadbeef->plug_get_list ();
+ for (int i = 0; plugins[i]; i++) {
+ DB_plugin_t *p = plugins[i];
+ if (p->id && !strcmp (p->id, "cover_loader")) {
+ fprintf (stderr, "gtkui: found cover-art loader plugin\n");
+ coverart_plugin = (DB_artwork_plugin_t *)p;
+ break;
+ }
+ }
+
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_ACTIVATE, DB_CALLBACK (gtkui_on_activate), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, DB_CALLBACK (gtkui_on_songchanged), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_TRACKINFOCHANGED, DB_CALLBACK (gtkui_on_trackinfochanged), 0);
diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c
index 3405e4fb..61fbef50 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -26,8 +26,7 @@
#include "support.h"
#include "drawing.h"
#include "trkproperties.h"
-
-#pragma GCC optimize("O0")
+#include "coverart.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -295,12 +294,15 @@ void main_draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbLis
int h = cwidth - group_y;
h = min (height, h);
gdk_draw_rectangle (drawable, GTK_WIDGET (listview)->style->white_gc, TRUE, x, y, width, h);
- GdkPixbuf *pixbuf = gdk_pixbuf_scale_simple ((GdkPixbuf *)play16_pixbuf, width, width, GDK_INTERP_BILINEAR);
- gdk_draw_pixbuf (drawable, GTK_WIDGET (listview)->style->white_gc, pixbuf, 0, group_y, x, y, width, h, GDK_RGB_DITHER_NONE, 0, 0);
- g_object_unref (pixbuf);
+// GdkPixbuf *pixbuf = gdk_pixbuf_scale_simple ((GdkPixbuf *)play16_pixbuf, width, width, GDK_INTERP_BILINEAR);
+ if (it) {
+ GdkPixbuf *pixbuf = get_cover_art (it, width);
+ gdk_draw_pixbuf (drawable, GTK_WIDGET (listview)->style->white_gc, pixbuf, 0, group_y, x, y, width, h, GDK_RGB_DITHER_NONE, 0, 0);
+ g_object_unref (pixbuf);
+ }
}
}
- else if (it == deadbeef->streamer_get_playing_track () && cinf->id == DB_COLUMN_PLAYING) {
+ else if (it && it == deadbeef->streamer_get_playing_track () && cinf->id == DB_COLUMN_PLAYING) {
int paused = deadbeef->get_output ()->state () == OUTPUT_STATE_PAUSED;
int buffering = !deadbeef->streamer_ok_to_read (-1);
uintptr_t pixbuf;