417 lines
15 KiB
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);
|
|
}
|