dockapps/wmhdplop/dockapp_imlib2.c

417 lines
15 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include "dockapp_imlib2.h"
#include <X11/extensions/shape.h>
#include <X11/Xutil.h>
#ifdef GKRELLM
#include <gdk/gdkx.h>
#endif
/* require ISO C99 compatibility */
#define DOCKIMLIB2_ERR(...) { fprintf(stderr, "DockImlib2 " DOCKIMLIB2_VERSION " error: "); \
fprintf(stderr, __VA_ARGS__); exit(1); }
#define DOCKIMLIB2_WARN(...) { fprintf(stderr, "DockImlib2 " DOCKIMLIB2_VERSION " warning: "); \
fprintf(stderr, __VA_ARGS__); exit(1); }
static void dockimlib2_set_rect_shape(DockImlib2 *dock, int x, int y, int w, int h) {
Pixmap mask = XCreatePixmap(dock->display, dock->win, dock->win_width, dock->win_height, 1); assert(mask);
GC gc = XCreateGC(dock->display, mask, 0, NULL);
XSetForeground(dock->display, gc, BlackPixel(dock->display, dock->screennum));
XFillRectangle(dock->display, mask, gc, 0, 0, dock->win_width, dock->win_height);
XSetForeground(dock->display, gc, WhitePixel(dock->display, dock->screennum));
XFillRectangle(dock->display, mask, gc, x,y,w,h);
XFreeGC(dock->display,gc);
/* setup shaped window */
XShapeCombineMask(dock->display, dock->normalwin, ShapeBounding,
0, 0, mask, ShapeSet);
if (dock->iconwin)
XShapeCombineMask(dock->display, dock->iconwin, ShapeBounding,
0, 0, mask, ShapeSet);
XFreePixmap(dock->display, mask);
}
/* some general windowmanager related functions ...*/
void set_window_title(Display *display, Window win, char *window_title, char *icon_title) {
int rc;
XTextProperty window_title_property;
/* window name */
rc = XStringListToTextProperty(&window_title,1, &window_title_property); assert(rc);
XSetWMName(display, win, &window_title_property);
XFree(window_title_property.value);
/* icon window name */
rc = XStringListToTextProperty(&icon_title,1, &window_title_property); assert(rc);
XSetWMIconName(display, win, &window_title_property);
XFree(window_title_property.value);
}
void
set_window_class_hint(Display *display, Window win, char *res_class, char *res_name) {
XClassHint *class_hint;
class_hint = XAllocClassHint();
class_hint->res_name = res_name;
class_hint->res_class = res_class;
XSetClassHint(display, win, class_hint);
XFree(class_hint);
}
#ifndef GKRELLM
static void dockimlib2_xinit(DockImlib2 *dock, DockImlib2Prefs *prefs) {
XSizeHints *xsh;
int i;
char *sdisplay = getenv("DISPLAY");
char *pgeom = NULL;
int undocked = 0;
char sdockgeom[40];
assert(prefs->argv); // this should be always set ..
if (prefs->flags & DOCKPREF_DISPLAY) sdisplay = prefs->display;
if (prefs->flags & DOCKPREF_GEOMETRY) { pgeom = prefs->geometry; undocked = 1; }
dock->display = XOpenDisplay(sdisplay);
if(!dock->display) DOCKIMLIB2_ERR("Couldn't connect to display %s\n", sdisplay);
dock->screennum = DefaultScreen(dock->display);
dock->visual = DefaultVisual(dock->display, dock->screennum);
dock->depth = DefaultDepth(dock->display, dock->screennum);
dock->colormap = DefaultColormap(dock->display, dock->screennum);
dock->rootwin = RootWindow(dock->display, dock->screennum);
dock->atom_WM_DELETE_WINDOW = XInternAtom(dock->display, "WM_DELETE_WINDOW", False);
dock->atom_WM_PROTOCOLS = XInternAtom(dock->display, "WM_PROTOCOLS", False);
/* set size hints */
xsh = XAllocSizeHints(); assert(xsh);
xsh->flags = 0;
xsh->width = dock->w;
xsh->height = dock->h;
xsh->x = xsh->y = 0;
snprintf(sdockgeom, sizeof sdockgeom, "%dx%d+0+0", prefs->dockapp_size, prefs->dockapp_size);
xsh->flags = XWMGeometry(dock->display, dock->screennum, pgeom, sdockgeom, 0,
xsh, &xsh->x, &xsh->y, &xsh->width, &xsh->height, &i);
if (undocked) {
dock->win_width = dock->w = xsh->width;
dock->win_height = dock->h = xsh->height;
dock->x0 = dock->y0 = 0;
}
xsh->base_width = xsh->width;
xsh->base_height = xsh->height;
xsh->flags |= USSize | PMinSize | PMaxSize | PSize;
xsh->min_height = 24; xsh->min_height = 24;
xsh->max_width = 500;
xsh->max_height = 500;
/* create the application window */
dock->normalwin = XCreateSimpleWindow(dock->display, dock->rootwin,
xsh->x, xsh->y, xsh->width, xsh->height, 0,
BlackPixel(dock->display, dock->screennum),
WhitePixel(dock->display, dock->screennum));
if(!dock->normalwin) DOCKIMLIB2_ERR("Couldn't create window\n");
if (!undocked) {
/* create icon window */
dock->iconwin = XCreateSimpleWindow(dock->display, dock->rootwin,
xsh->x, xsh->y, xsh->width, xsh->height, 0,
BlackPixel(dock->display, dock->screennum),
WhitePixel(dock->display, dock->screennum));
if(!dock->iconwin) DOCKIMLIB2_ERR("Couldn't create icon window\n");
dock->win = dock->iconwin;
} else {
dock->iconwin = None;
dock->win = dock->normalwin;
}
dock->iconwin_mapped = dock->normalwin_mapped = 1; /* by default */
/* start with an empty window in order to get the background pixmap */
dockimlib2_set_rect_shape(dock,32,32,1,0);
/* set window manager hints */
if (!undocked) {
XWMHints *xwmh;
xwmh = XAllocWMHints();
xwmh->flags = WindowGroupHint | IconWindowHint | StateHint;
xwmh->icon_window = dock->iconwin;
xwmh->window_group = dock->normalwin;
xwmh->initial_state = WithdrawnState;
XSetWMHints(dock->display, dock->normalwin, xwmh);
XFree(xwmh); xwmh = NULL;
}
set_window_class_hint(dock->display, dock->normalwin, prefs->argv[0], prefs->argv[0]);
/* set size hints */
XSetWMNormalHints(dock->display, dock->normalwin, xsh);
set_window_title(dock->display, dock->normalwin, "wmhdplop", "wmhdplop");
/* select events to catch */
{
long evmask = ExposureMask | ButtonPressMask | ButtonReleaseMask | VisibilityChangeMask |
PointerMotionMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
XSelectInput(dock->display, dock->normalwin, evmask);
if (dock->iconwin)
XSelectInput(dock->display, dock->iconwin, evmask);
}
XSetWMProtocols(dock->display, dock->normalwin, &dock->atom_WM_DELETE_WINDOW, 1);
/* set the command line for restarting */
XSetCommand(dock->display, dock->normalwin, prefs->argv, prefs->argc);
/* map the main window */
XMapWindow(dock->display, dock->normalwin);
XFree(xsh); xsh = NULL;
}
#else /* GKRELLM */
void dockimlib2_gkrellm_xinit(DockImlib2 *dock, GdkDrawable *gkdrawable) {
dock->display = GDK_WINDOW_XDISPLAY(gkdrawable);
dock->visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(gkdrawable));
dock->depth = gdk_drawable_get_depth(gkdrawable);
dock->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gkdrawable));
dock->screennum = DefaultScreen(dock->display);
dock->rootwin = RootWindow(dock->display, dock->screennum);
dock->normalwin = XCreateSimpleWindow(dock->display, GDK_PIXMAP_XID(gkdrawable),
0, 0, dock->w, dock->h, 0,
BlackPixel(dock->display, dock->screennum),
WhitePixel(dock->display, dock->screennum));
//dock->normalwin = GDK_PIXMAP_XID(gkdrawable); // CA CLIGNOTE !!!
dock->iconwin = None; dock->iconwin_mapped = 0;
dock->win = dock->normalwin; dock->normalwin_mapped = 1;
/* start with an empty window in order to get the background pixmap */
dockimlib2_set_rect_shape(dock,32,32,1,0);
/* map the main window */
XMapWindow(dock->display, dock->normalwin);
}
#endif /* GKRELLM */
static void add_fontpath(const char *path, int recurse) {
struct stat st;
if (stat(path,&st) != 0 ||
!S_ISDIR(st.st_mode)) return;
if (recurse > 3) return; /* prevent scanning of whole hd/infinite recursions in case of a bad symlink */
printf("add font path: '%s'\n", path);
imlib_add_path_to_font_path(path);
if (recurse) {
DIR *d = opendir(path);
struct dirent *de;
if (!d) return;
while ((de = readdir(d))) {
char s[1024];
if (strcmp(de->d_name,".") == 0 ||
strcmp(de->d_name,"..") == 0) continue;
snprintf(s,sizeof s,"%s/%s",path, de->d_name);
add_fontpath(s,recurse+1);
}
closedir(d);
}
}
void dockimlib2_reset_imlib(DockImlib2 *dock) {
imlib_free_image();
dock->img = imlib_create_image(dock->w, dock->h);
imlib_context_set_image(dock->img);
imlib_context_set_drawable(dock->win);
dockimlib2_set_rect_shape(dock, dock->x0, dock->y0, dock->w, dock->h);
}
/* setup some default values for imlib2 */
static void dockimlib2_setup_imlib(DockImlib2 *dock) {
char fp[512];
/* set the maximum number of colors to allocate for 8bpp and less to 32 */
imlib_set_color_usage(32);
/* dither for depths < 24bpp */
imlib_context_set_dither(1);
/* set the display , visual, colormap and drawable we are using */
imlib_context_set_display(dock->display);
imlib_context_set_visual(dock->visual);
imlib_context_set_colormap(dock->colormap);
imlib_context_set_drawable(dock->win);
dock->img = imlib_create_image(dock->w, dock->h);
imlib_context_set_image(dock->img);
/* some default font paths */
snprintf(fp, 512, "%s/.fonts", getenv("HOME"));
add_fontpath(fp,1);
/*add_fontpath("/usr/share/fonts/truetype",1);
add_fontpath("/usr/share/fonts/ttf",1);*/
add_fontpath("/usr/share/fonts",1);
add_fontpath("/usr/X11R6/lib/X11/fonts/truetype",1);
add_fontpath("/usr/X11R6/lib/X11/fonts/TrueType",1);
add_fontpath("/usr/X11R6/lib/X11/fonts/ttf",1);
add_fontpath("/usr/X11R6/lib/X11/fonts/TTF",1);
/*imlib_add_path_to_font_path(fp);
imlib_add_path_to_font_path("/usr/share/fonts/truetype");
imlib_add_path_to_font_path("/usr/share/fonts/truetype/freefont");
imlib_add_path_to_font_path("/usr/share/fonts/truetype/ttf-bitstream-vera");
imlib_add_path_to_font_path("/usr/share/fonts/ttf/vera");*/ /* vera on mdk */
imlib_context_set_TTF_encoding(IMLIB_TTF_ENCODING_ISO_8859_1);
//imlib_set_cache_size(0);imlib_set_font_cache_size(0);
}
/* wait for the dockapp to be swallowed and grab the background pixmap */
static void dockimlib2_xstartup(DockImlib2 *dock) {
dock->bg = NULL;
dockimlib2_set_rect_shape(dock, dock->x0, dock->y0, dock->w, dock->h);
#if 0
Window parent = 0;
int exposed = 0, mapped = 0;
printf("xstartup..\n");
do {
XEvent event;
XNextEvent(dock->display, &event);
switch (event.type) {
case ReparentNotify: {
XReparentEvent ev = event.xreparent;
if (ev.window == dock->win) {
parent = ev.parent;
}
} break;
case MapNotify: {
XMappingEvent ev = event.xmapping;
printf("MapNotify: ev.win = %lx\n", ev.window);
if (ev.window == dock->win) mapped = 1;
} break;
case Expose: {
XExposeEvent ev = event.xexpose;
printf("Expose: ev.win = %lx\n", ev.window);
if (ev.window == dock->win) exposed = 1;
} break;
}
} while (parent == 0 && !exposed && !mapped);
if (parent == dock->rootwin) {
printf("... oups, parent window is rootwin ... are you really running windowmaker?\n");
dock->bg = imlib_create_image(dock->w, dock->h);
} else {
imlib_context_set_drawable(parent);
dock->bg = imlib_create_image_from_drawable(0, dock->x0, dock->y0, dock->w, dock->h, 1);
imlib_context_set_drawable(dock->win);
dockimlib2_set_rect_shape(dock, dock->x0, dock->y0, dock->w, dock->h);
}
printf("xstartup : success\n");
#endif
}
#ifndef GKRELLM
DockImlib2* dockimlib2_setup(int x0, int y0, int w, int h, DockImlib2Prefs *prefs) {
#else
DockImlib2* dockimlib2_gkrellm_setup(int x0, int y0, int w, int h, DockImlib2Prefs *prefs, GdkDrawable *gkdrawable) {
#endif
DockImlib2 *dock = calloc(1,sizeof(DockImlib2)); assert(dock);
//gdk_drawable_get_size(gkdrawable, &dock->win_width, &dock->win_height);
//printf("x0=%d, y0=%d, width = %d,%d, height = %d,%d\n", x0,y0,w,h,dock->win_width, dock->win_height);
dock->win_width = w+x0; dock->win_height = h+y0;//DOCK_WIDTH;
dock->x0 = x0; dock->y0 = y0;
dock->w = w; dock->h = h;
#ifndef GKRELLM
dockimlib2_xinit(dock, prefs);
#else
(void) prefs;
dockimlib2_gkrellm_xinit(dock, gkdrawable);
#endif
dockimlib2_setup_imlib(dock);
dockimlib2_xstartup(dock);
return dock;
}
static char *last_font_name = 0;
const char* dockimlib2_last_loaded_font() { return last_font_name; }
Imlib_Font *imlib_load_font_nocase(const char *name) {
Imlib_Font *f;
int i;
if (last_font_name) free(last_font_name);
last_font_name = strdup(name);
if ((f = imlib_load_font(last_font_name))) return f;
for (i=0; last_font_name[i]; ++i) last_font_name[i] = tolower(last_font_name[i]);
if ((f = imlib_load_font(last_font_name))) return f;
for (i=0; last_font_name[i]; ++i) last_font_name[i] = toupper(last_font_name[i]);
f = imlib_load_font(last_font_name);
return f;
}
Imlib_Font *load_font(char *prefname, char **flist_) {
Imlib_Font *f = NULL;
char **flist = flist_;
if (prefname) {
f = imlib_load_font_nocase(prefname);
if (!f) {
int i,np; char **s;
fprintf(stderr, "warning: could not find font '%s' in the font path:\n",prefname);
s = imlib_list_font_path(&np);
for (i=0; i < np; ++i) fprintf(stderr, " %s\n", s[i]);
} else {
printf("loaded font %s\n", prefname);
}
}
if (!f) {
for (; *flist; ++flist) {
if ((f = imlib_load_font_nocase(*flist))) {
printf("loaded font %s\n", *flist); break;
}
}
if (!f) {
fprintf(stderr, "could not load a default ttf font .. I tried ");
flist = flist_;
for (; *flist; ++flist)
fprintf(stderr, "'%s'%s", *flist, (flist[1]?", ":""));
fprintf(stderr, "\nUse the --font* options to change the fontpath/fontnames\n");
}
}
return f;
}
/*
merges dock->bg and dock->img, and renders the result on the window
this function does not alter the imlib context
*/
void dockimlib2_render(DockImlib2 *dock) {
Pixmap olddrawable = imlib_context_get_drawable();
Imlib_Image oldimage = imlib_context_get_image();
//imlib_context_set_drawable(dock->win);
imlib_context_set_image(dock->img);
if (imlib_image_has_alpha()) {
imlib_context_set_image(dock->bg);
Imlib_Image bg = imlib_clone_image();
imlib_context_set_image(bg);
imlib_blend_image_onto_image(dock->img, 0, 0, 0, dock->w, dock->h, 0, 0, dock->w, dock->h);
if (dock->normalwin) {
imlib_context_set_drawable(dock->normalwin);
imlib_render_image_on_drawable(dock->x0, dock->y0);
}
if (dock->iconwin) {
imlib_context_set_drawable(dock->iconwin);
imlib_render_image_on_drawable(dock->x0, dock->y0);
}
/* XSetWindowBackgroundPixmap(dock->display, dock->GKwin, dock->win);
XClearWindow(dock->display, dock->GKWin); */
imlib_free_image();
} else {
if (dock->normalwin_mapped && dock->normalwin) {
imlib_context_set_drawable(dock->normalwin);
imlib_render_image_on_drawable(dock->x0, dock->y0); /* imlib_render_image_on_drawable generates many pages faults !? */
}
if (dock->iconwin_mapped && dock->iconwin) {
imlib_context_set_drawable(dock->iconwin);
imlib_render_image_on_drawable(dock->x0, dock->y0);
}
}
imlib_context_set_image(oldimage);
imlib_context_set_drawable(olddrawable);
}