+// Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
+// see below for copyright information on the second portion of this file
+
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <gcj/cni.h>
+#include <signal.h>
#include <java/lang/String.h>
#include <org/xwt/Surface.h>
static XShmSegmentInfo shm_info;
static Window selectionWindow;
static int shm_supported;
+static int shm_pixmaps_supported;
static int screen_num;
static int colorDepth = 0;
static Display* display;
+static int shm_size = 0;
-#define min(a, b) (a < b ? a : b)
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) < (b) ? (b) : (a))
// X11DoubleBuffer //////////////////////////////////////////////////////////////////////
-void org::xwt::plat::POSIX$X11DoubleBuffer::drawPicture(org::xwt::Picture* s,
- jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
-
- if (pm == NULL) return;
+// ensures that the shared memory is at least size bytes; if not, allocates 3/2 * size
+static void ensureShmSize(int size) {
+ if (size > shm_size) {
+ if (shm_size > 0) {
+ XShmDetach(display, &shm_info);
+ shmdt(shm_info.shmaddr);
+ shmctl(shm_info.shmid, IPC_RMID, 0);
+ }
+ shm_size = 3 * size / 2;
+ shm_info.shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0777 | IPC_EXCL);
+ shm_info.shmaddr = (char*)shmat(shm_info.shmid, 0, 0);
+ shm_info.readOnly = False;
+ XSync(display, False);
+ shmctl(shm_info.shmid, IPC_RMID, 0);
+ XShmAttach(display, &shm_info);
+ XSync(display, False);
+ }
+}
+
+void org::xwt::plat::POSIX$X11DoubleBuffer::fastDrawPicture(org::xwt::Picture* s,
+ jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
org::xwt::plat::POSIX$X11Picture* source = (org::xwt::plat::POSIX$X11Picture*)s;
-
- int scaling = dx2 - dx1 != sx2 - sx1 || dy2 - dy1 != sy2 - sy1;
-
- // FIXME: this needs to be moved into the fastpath-only to prevent image wriggling
+
+ // it's safe to clip manually since we no that no scaling will be done
if (dx1 < clipx) { sx1 += ((clipx - dx1) * (sx2 - sx1)) / (dx2 - dx1); dx1 = clipx; }
if (dy1 < clipy) { sy1 += ((clipy - dy1) * (sy2 - sy1)) / (dy2 - dy1); dy1 = clipy; }
if (dx2 > clipx + clipw) { sx2 -= ((dx2 - clipx - clipw) * (sx2 - sx1)) / (dx2 - dx1); dx2 = clipx + clipw; }
if (dy2 > clipy + cliph) { sy2 -= ((dy2 - clipy - cliph) * (sy2 - sy1)) / (dy2 - dy1); dy2 = clipy + cliph; }
if (dx1 > clipx + clipw) return;
if (dy1 > clipy + cliph) return;
-
if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0) return;
-
- // fastpath: if the X11Picture has a pixmap, and no scaling, and all-or-nothing alpha
- if (!scaling && source->doublebuf != NULL) {
- if (source->doublebuf->stipple != NULL) {
- XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
- XSetClipOrigin(display, (*((GC*)clipped_gc)), dx1 - sx1, dy1 - sy1);
- } else {
- XSetClipMask(display, (*((GC*)clipped_gc)), None);
- }
- XCopyArea(display, *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)), sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1);
- return;
+
+ if (source->doublebuf->stipple != NULL) {
+ XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
+ XSetClipOrigin(display, (*((GC*)clipped_gc)), dx1 - sx1, dy1 - sy1);
+ } else {
+ XSetClipMask(display, (*((GC*)clipped_gc)), None);
}
+ XCopyArea(display, *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)), sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1);
+}
- // slowpath: true alpha or scaling
-
- // the following optimizations were abandoned because they don't
- // improve performance in the presence of XSHM extensions, and
- // therefore aren't worth the code-bloat:
- // - scaling clipmask bitmaps (and caching them)
- // - caching pre-scaled XImages
-
- // ximage from our destination -- if true_alpha is false, we can use malloc() instead of XGetImage
+void org::xwt::plat::POSIX$X11DoubleBuffer::slowDrawPicture(org::xwt::Picture* s,
+ jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
+
+ org::xwt::plat::POSIX$X11Picture* source = (org::xwt::plat::POSIX$X11Picture*)s;
XImage* xi;
-
- if (force_slowpath && shm_supported) {
-
- // if the shared memory area is unsuitable, destroy it
-
- if (((XImage*)shm_ximage) != NULL && (dx2 - dx1 != ((XImage*)shm_ximage)->width || dy2 - dy1 != ((XImage*)shm_ximage)->height)) {
- XShmDetach(display, &shm_info);
- XDestroyImage(((XImage*)shm_ximage));
- }
-
- // FIXME: replace 4 with something sensible
- if (((XImage*)shm_ximage) != NULL && (dx2 - dx1) * (dy2 - dy1) * 4 < old_shmsize) {
- shmdt(shm_info.shmaddr);
- shmctl(shm_info.shmid, IPC_RMID, 0);
- memset(&shm_info, 0, sizeof(XShmSegmentInfo));
- shm_info.shmaddr = NULL;
- }
-
- // if we need to recreate the shared memory area
- if (shm_info.shmaddr == NULL) {
- old_shmsize = xi->bytes_per_line * xi->height;
- memset(&shm_info, 0, sizeof(XShmSegmentInfo));
- shm_info.shmid = shmget(IPC_PRIVATE, xi->bytes_per_line * xi->height, IPC_CREAT | 0777 | IPC_EXCL);
- shm_info.shmaddr = xi->data = (char*)shmat(shm_info.shmid, 0, 0);
- shm_info.readOnly = False;
-
- XSync(display, False);
- shmctl(shm_info.shmid, IPC_RMID, 0);
- XShmAttach(display, &shm_info);
- XSync(display, False);
- }
-
- xi = ((XImage*)shm_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, shm_info.shmaddr, &shm_info, dx2 - dx1, dy2 - dy1);
-
- } else if (shared_pixmap && shm_supported) {
- xi = ((XImage*)mxi);
+
+ // FASTEST: shared pixmap; twiddle bits in video ram directly
+ if (shared_pixmap) {
+ XSync(display, False); // ensure that all pending operations have rendered
+ xi = (XImage*)fake_ximage;
+
+ // MEDIUM: write to a shared ximage, then ask the server to do the blit
+ } else if (shm_supported) {
+ xi = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, &shm_info, dx2 - dx1, dy2 - dy1);
+ ensureShmSize(xi->bytes_per_line * xi->height);
+ xi->data = shm_info.shmaddr;
+ XShmGetImage(display, (*((Pixmap*)pm)), xi, dx1, dy1, AllPlanes);
+ // SLOWEST: write to an ximage, copy it through the TCP connection, ask the server to do the blit
} else {
xi = XGetImage(display, (*((Pixmap*)pm)), dx1, dy1, dx2 - dx1, dy2 - dy1, AllPlanes, ZPixmap);
-
}
- // FIXME: xoffset?
- // FIXME: optimize pixels that have 0xFF or 0x00 alpha
- // endian issues
-
-
- // further assumption: the only time source->data will be null is
- // if we're drawing from a bordercache -- but those don't get
- // stretched.
- if (source->data == NULL || elements(source->data) == NULL) {
- printf("AIEEEEE %i %i %i %i\n", dx2 - dx1, dy2 - dy1, sx2 - sx1, sy2 - sy1);
- return;
- }
int* sourcedata = (int*)elements(source->data);
-
- for(int y=dy1; y<dy2; y++) {
+ for(int y=max(dy1, clipy); y<min(dy2, clipy + cliph); y++) {
- if (y < clipy || y >= clipy + cliph) continue;
+ char* current_pixel = (xi->data + y * xi->bytes_per_line) +
+ (shared_pixmap ? max(dx1, clipx) * (xi->bits_per_pixel / 8) : - 1 * dy1 * xi->bytes_per_line);
- char* bitstart;
- if (shared_pixmap && shm_supported) {
- // FIXME: not sure if bitmap_unit is the right thing
- bitstart = xi->data + y * xi->bytes_per_line + dx1 * (xi->bits_per_pixel / 8);
- } else {
- bitstart = xi->data + (y - dy1) * xi->bytes_per_line;
- }
-
- for(int x=dx1; x<dx2; x++, bitstart += xi->bits_per_pixel / 8) {
-
- if (x < clipx || x >= clipx + clipw) continue;
-
+ for(int x=max(dx1, clipx); x<min(dx2, clipx + clipw); x++, current_pixel += xi->bits_per_pixel / 8) {
int source_x = ((x - dx1) * (sx2 - sx1)) / (dx2 - dx1) + sx1;
int source_y = ((y - dy1) * (sy2 - sy1)) / (dy2 - dy1) + sy1;
- // note that we can assume that source->data exists here, since writeable PixelGrids (ie
- // doublebuffers) never have true_alpha, and are never scaled.
int sourcepixel = sourcedata[source_x + source_y * source->getWidth()];
int alpha = (sourcepixel & 0xFF000000) >> 24;
int source_red = (sourcepixel & 0x00FF0000) >> 16;
int source_blue = (sourcepixel & 0x000000FF);
int red = 0, blue = 0, green = 0;
+ if (alpha == 0x00) continue;
if (alpha != 0xFF) {
int targetpixel;
switch (xi->bits_per_pixel) {
- case 8: targetpixel = (int)(*bitstart); break;
- case 16: targetpixel = (int)(*((u_int16_t*)bitstart)); break;
- case 24: targetpixel = (((int)*bitstart) << 16) | (((int)*(bitstart + 1)) << 8) | (((int)*(bitstart + 2))); break;
- case 32: targetpixel = *((int*)bitstart); break;
+ case 8: targetpixel = (int)(*current_pixel); break;
+ case 16: targetpixel = (int)(*((u_int16_t*)current_pixel)); break;
+ case 24: targetpixel = (((int)*current_pixel) << 16) | (((int)*(current_pixel + 1)) << 8) | (((int)*(current_pixel + 2))); break;
+ case 32: targetpixel = *((int*)current_pixel); break;
default: org::xwt::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
}
red = ((source_red * colormap_info->red_max * alpha) + (red * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
green = ((source_green * colormap_info->green_max * alpha) + (green * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
blue = ((source_blue * colormap_info->blue_max * alpha) + (blue * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
-
- int destpixel = red * colormap_info->red_mult + green * colormap_info->green_mult +
+ u_int32_t destpixel = red * colormap_info->red_mult + green * colormap_info->green_mult +
blue * colormap_info->blue_mult + colormap_info->base_pixel;
-
+
switch (xi->bits_per_pixel) {
- case 8: *bitstart = (char)(destpixel & 0xFF); break;
- case 16: *((u_int16_t*)bitstart) = (u_int16_t)destpixel; break;
- case 24: break; // FIXME, unimplemented
- case 32: *((int*)bitstart) = destpixel; break;
+ case 8: *current_pixel = (char)(destpixel & 0xFF); break;
+ case 16: *((u_int16_t*)current_pixel) = (u_int16_t)destpixel; break;
+ case 24: {
+ int offset = (int)current_pixel & 0x3;
+ u_int64_t dest = ((u_int64_t)destpixel) << (8 * offset);
+ u_int64_t mask = ((u_int64_t)0xffffff) << (8 * offset);
+ u_int64_t* base = (u_int64_t*)(current_pixel - offset);
+ *base = (*base & ~mask) | dest;
+ break;
+ }
+ case 32: *((u_int32_t*)current_pixel) = destpixel; break;
default: org::xwt::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
}
-
}
}
- if (force_slowpath && shm_supported) {
- // watch for concurrency issues if we're going to keep the shm region around
- XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1, False);
+ if (shared_pixmap) {
+ // do nothing, we wrote directly to video memory
- } if (shared_pixmap && shm_supported) {
- // do nothing, it's all taken care of
+ } else if (shm_supported) {
+ XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1, False);
+ XDestroyImage(xi);
} else {
XPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1);
}
}
+void org::xwt::plat::POSIX$X11DoubleBuffer::finalize() {
+ if (shared_pixmap) {
+ XShmSegmentInfo *sinfo = (XShmSegmentInfo*)shm_segment;
+ XShmDetach(display, sinfo);
+ shmdt(sinfo->shmaddr);
+ shmctl(sinfo->shmid, IPC_RMID, 0);
+ XDestroyImage((XImage*)fake_ximage);
+ free(sinfo);
+ }
+ if (stipple) {
+ XFreePixmap(display, *((Pixmap*)stipple));
+ free(stipple);
+ }
+ XFreePixmap(display, *((Pixmap*)pm));
+ XFreeGC(display, *((GC*)gc));
+ XFreeGC(display, *((GC*)clipped_gc));
+}
+
void org::xwt::plat::POSIX$X11DoubleBuffer::natInit() {
if (width == 0 || height == 0) return;
-
+ shared_pixmap &= shm_supported & shm_pixmaps_supported; // refuse to use shared pixmaps if we don't have shm
pm = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
- if (shared_pixmap && shm_supported) {
-
- // FIXME: check if server pixmaps are XYPixmaps
- printf("CREATING SHARED (*((Pixmap*)pm)) %i %i\n", width, height);
-
+ if (!shared_pixmap)
+ (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, colorDepth);
+ else {
XShmSegmentInfo *sinfo = (XShmSegmentInfo*)malloc(sizeof(XShmSegmentInfo));
- ((XImage*)mxi) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
-
- memset(sinfo, 0, sizeof(XShmSegmentInfo));
-
- sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)mxi)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
- ((XImage*)mxi)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
+ shm_segment = (gnu::gcj::RawData*)sinfo;
+ ((XImage*)fake_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
+ sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)fake_ximage)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
+ ((XImage*)fake_ximage)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
sinfo->readOnly = False;
XShmAttach(display, sinfo);
-
XSync(display, False);
shmctl(sinfo->shmid, IPC_RMID, 0);
-
- (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, 0), sinfo->shmaddr, sinfo, width, height, colorDepth);
+ (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, screen_num), sinfo->shmaddr, sinfo, width, height, colorDepth);
XSync(display, False);
-
- } else {
- (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, 0), width, height, colorDepth);
-
}
+
gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
clipped_gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
(*((GC*)gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
void org::xwt::plat::POSIX$X11DoubleBuffer::createStipple(org::xwt::plat::POSIX$X11Picture* xpi) {
stipple = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
- (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, 0), width, height, 1);
+ (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, 1);
XImage xi;
xi.data = (char*)malloc((width + 1) * height);
XGCValues vm;
vm.graphics_exposures = 0;
- XChangeGC(display, (*((GC*)stipple_gc)), GCGraphicsExposures, &vm);
+ XChangeGC(display, stipple_gc, GCGraphicsExposures, &vm);
XPutImage(display, (*((Pixmap*)stipple)), stipple_gc, &xi, 0, 0, 0, 0, width, height);
}
if (y < clipy) { h -= (clipy - y); y = clipy; }
if (x + w > clipx + clipw) w = (clipx + clipw - x);
if (y + h > clipy + cliph) h = (cliph + clipy - y);
-
+
XSetForeground(display, (*((GC*)gc)),
((((argb & 0x00FF0000) >> 16) * colormap_info->red_max) / 0xFF) * colormap_info->red_mult +
((((argb & 0x0000FF00) >> 8) * colormap_info->green_max) / 0xFF) * colormap_info->green_mult +
);
XFillRectangle(display, (*((Pixmap*)pm)), (*((GC*)gc)), x, y, w, h);
-
}
void org::xwt::plat::POSIX$X11DoubleBuffer::drawString(::java::lang::String* font, ::java::lang::String* text, jint x, jint y, jint argb) {
);
// Grab the string
- char buf[text->length() + 1];
- JvGetStringUTFRegion(text, 0, text->length(), buf);
- buf[text->length()] = '\0';
+ int len = min(1024, JvGetStringUTFLength(text));
+ char buf[len + 1];
+ JvGetStringUTFRegion(text, 0, len, buf);
+ buf[len] = '\0';
// Build the XTextItem structure
XTextItem textitem;
textitem.chars = buf;
- textitem.nchars = text->length();
+ textitem.nchars = len;
textitem.delta = 0;
textitem.font = ((XFontStruct*)org::xwt::plat::POSIX::fontToXFont(font))->fid;
// X11Surface //////////////////////////////////////////////////////////////////////
+void org::xwt::plat::POSIX$X11Surface::setIcon(org::xwt::Picture* pic) {
+ org::xwt::plat::POSIX$X11Picture* p = ((org::xwt::plat::POSIX$X11Picture*)pic);
+ org::xwt::plat::POSIX$X11DoubleBuffer* old_dbuf = p->doublebuf;
+ p->buildDoubleBuffer(1);
+ XWMHints xwmh;
+ memset(&xwmh, 0, sizeof(XWMHints));
+ xwmh.flags |= IconPixmapHint | IconMaskHint;
+ xwmh.icon_pixmap = *((Pixmap*)p->doublebuf->pm);
+ xwmh.icon_mask = *((Pixmap*)p->doublebuf->stipple);
+ XSetWMHints(display, (*((Window*)window)), &xwmh);
+ p->doublebuf = old_dbuf;
+}
+
void org::xwt::plat::POSIX$X11Surface::setTitleBarText(java::lang::String* s) {
int len = min(JvGetStringUTFLength(s), 1024);
char buf[len + 1];
void org::xwt::plat::POSIX$X11Surface::toFront() { XRaiseWindow(display, (*((Window*)window))); }
void org::xwt::plat::POSIX$X11Surface::toBack() { XLowerWindow(display, (*((Window*)window))); }
+void org::xwt::plat::POSIX$X11Surface::setInvisible(jboolean i) {
+ if (i) XUnmapWindow(display, (*((Window*)window)));
+ else XMapRaised(display, (*((Window*)window)));
+ XFlush(display);
+}
+
void org::xwt::plat::POSIX$X11Surface::_setMinimized(jboolean b) {
if (b) XIconifyWindow(display, (*((Window*)window)), screen_num);
else XMapRaised(display, (*((Window*)window)));
+ XFlush(display);
}
void org::xwt::plat::POSIX$X11Surface::natInit() {
KeyPressMask | KeyReleaseMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
PointerMotionMask | ButtonMotionMask | ConfigureNotify | FocusChangeMask;
- *((Window*)window) = XCreateWindow(display, DefaultRootWindow(display), 10, 10, 500, 300, 0,
+ *((Window*)window) = XCreateWindow(display, RootWindow(display, screen_num), 10, 10, 500, 300, 0,
colorDepth, InputOutput, CopyFromParent,
CWColormap | CWBitGravity | CWEventMask, &xswa);
if (!framed) {
- // FIXME: figure out why this works and make it elegant
+ // I don't know why this works....
int dat[5] = { 0x2, 0xbffff804, 0x0, 0x817f560, 0x8110694 };
XChangeProperty(display, (*((Window*)window)),
XInternAtom(display, "_MOTIF_WM_HINTS", False),
Window child;
int x_out, y_out;
XConfigureEvent* xce = (XConfigureEvent*)(e);
- XTranslateCoordinates(display, (*((Window*)window)), DefaultRootWindow(display), 0, 0, &x_out, &y_out, &child);
+ XTranslateCoordinates(display, (*((Window*)window)), RootWindow(display, screen_num), 0, 0, &x_out, &y_out, &child);
if (xce->width != width || xce->height != height) SizeChange(xce->width, xce->height);
if (x_out != root->abs(0) || y_out != root->abs(1)) PosChange(x_out, y_out);
jint org::xwt::plat::POSIX::_getScreenWidth() { return WidthOfScreen(DefaultScreenOfDisplay(display)); }
jint org::xwt::plat::POSIX::_getScreenHeight() { return HeightOfScreen(DefaultScreenOfDisplay(display)); }
+jstring org::xwt::plat::POSIX::getBrowserEnvString() {
+ char* envstr = getenv("BROWSER");
+ return envstr == NULL ? NULL : JvNewStringLatin1(envstr);
+}
+
+void org::xwt::plat::POSIX::spawnChildProcess(JArray<jstring>* cmd) {
+ jstring* cmdstrings = elements(cmd);
+ char* cmd2[cmd->length + 1];
+ cmd2[cmd->length] = NULL;
+ for(int i=0; i<cmd->length; i++) {
+ cmd2[i] = (char*)malloc(JvGetStringUTFLength(cmdstrings[i]));
+ JvGetStringUTFRegion(cmdstrings[i], 0, JvGetStringUTFLength(cmdstrings[i]), cmd2[i]);
+ }
+
+ if (!fork()) {
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ execvp(cmd2[0], cmd2);
+ }
+}
+
void org::xwt::plat::POSIX::eventThread() {
XEvent e;
while(true) {
XSetSelectionOwner(display, XInternAtom(display, "PRIMARY", 0), selectionWindow, CurrentTime);
}
+typedef int (X11ErrorHandler)(Display*, XErrorEvent*);
+int errorHandler(Display* d, XErrorEvent* e) {
+ // this error handler is only installed during the initial
+ // test to see if shm is present
+ java::lang::System::out->println(JvNewStringLatin1("here"));
+ shm_supported = 0;
+}
+
void org::xwt::plat::POSIX::natInit() {
if (!XInitThreads())
screen_num = XDefaultScreen(display);
colorDepth = (jint)(DefaultDepth(((Display*)display), 0));
shm_info.shmaddr = NULL;
+
shm_supported = (XShmQueryExtension(display) == True);
- //shm_supported = 0;
+ if (shm_supported) {
+ X11ErrorHandler* oldHandler = XSetErrorHandler(errorHandler);
+ XShmSegmentInfo sinfo;
+ sinfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT | 0777 | IPC_EXCL);
+ sinfo.readOnly = False;
+ // if the server is remote, this will trigger the error handler
+ XShmAttach(display, &sinfo);
+ XSync(display, False);
+ XSetErrorHandler(oldHandler);
+ }
+
+ if (shm_supported)
+ shm_pixmaps_supported = (XShmPixmapFormat(display) == ZPixmap);
crosshair = JvNewStringLatin1("crosshair");
east = JvNewStringLatin1("east");
wait_cursor = XCreateFontCursor(display, XC_watch);
default_cursor = XCreateFontCursor(display, XC_left_ptr);
- selectionWindow = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
+ selectionWindow = XCreateWindow(display, RootWindow(display, screen_num), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
visual = DefaultVisual(display, screen_num);
char buf[255];
sprintf(buf, "X11 SHM: %s", shm_supported ? "enabled" : "disabled");
//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// //
+// Everything below this point was taken, cut-and-paste, from the //
+// source for libXmu. It implements the official 'standard colormap //
+// creation algorithm. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
/* $Xorg: LookupCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
// Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
package org.xwt.plat;
-// FIXME: protected void _newBrowserWindow(String url)
-// FIXME: When should I use RootWindow versus DefaultRootWindow?
-// FIXME: Solaris: xwt.altKeyName -> "Meta"
-// FIXME: minimize/taskbar icon
-// FIXME: 15bpp? can't assume depth/8 == bytespp
-// FIXME: check for x resource / memory leaks
-// FIXME: WM_HINTS flags: icon pixmap, icon window [[ have to wait until we have gnome/kde wm's installed ]]
-// FIXME: code-review POSIX.cc
-
import java.awt.*;
import java.awt.image.*;
import gnu.gcj.RawData;
// General Methods ///////////////////////////////////////////////////////
+ protected String _getAltKeyName() { return System.getProperty("os.name", "").indexOf("SunOS") != -1 ? "Meta" : "Alt"; }
protected String[] _listFonts() { return fontList; }
protected String getDescriptiveName() { return "GCJ Linux Binary"; }
protected Picture _createPicture(int[] data, int w, int h) { return new POSIX.X11Picture(data, w, h); }
protected native void eventThread();
private native void natInit();
+ /** returns the $BROWSER environment variable, since System.getenv() is useless */
+ private static native String getBrowserEnvString();
+
+ /** spawns a process which is immune to SIGHUP */
+ private static native void spawnChildProcess(String[] command);
+
+ protected void _newBrowserWindow(String url) {
+ String browserString = getBrowserEnvString();
+ if (browserString == null) {
+ browserString = "netscape " + url;
+ } else if (browserString.indexOf("%s") != -1) {
+ browserString =
+ browserString.substring(0, browserString.indexOf("%s")) +
+ url + browserString.substring(browserString.indexOf("%s") + 2);
+ } else {
+ browserString += " " + url;
+ }
+
+ StringTokenizer st = new StringTokenizer(browserString, " ");
+ String[] cmd = new String[st.countTokens()];
+ for(int i=0; st.hasMoreTokens(); i++) {
+ cmd[i] = st.nextToken();
+ System.out.println(i + ":" + cmd[i]);
+ }
+
+ spawnChildProcess(cmd);
+ }
+
public POSIX() { }
public void init() {
natInit();
boolean framed = false;
Semaphore waitForCreation = new Semaphore();
- public void setIcon(Picture p) { /* FIXME */ }
- public void setInvisible(boolean i) { /* FIXME */ }
+ public native void setInvisible(boolean i);
public void _setMaximized(boolean m) { if (Log.on) Log.log(this, "POSIX/X11 can't maximize windows"); }
+ public native void setIcon(Picture p);
public native void _setMinimized(boolean b);
public native void setTitleBarText(String s);
public native void setSize(int w, int h);
// Our Subclass of Picture ///////////////////////////////////////////////
- // FIXME: what if display server runs out of pixmap space? Think resource conservation...
-
- /** Implements a Picture as an X11 Pixmap */
+ /**
+ * Implements a Picture. No special X11 structure is created
+ * unless the image has no alpha (in which case a
+ * non-shared-pixmap DoubleBuffer is created), or all-or-nothing
+ * alpha (in which case a non-shared-pixmap DoubleBuffer with a
+ * stipple bitmap is created).
+ */
public static class X11Picture implements Picture {
int width;
this.data = data;
this.width = w;
this.height = h;
+ boolean needsStipple = false;
// if we have any non-0x00, non-0xFF alphas, we can't double buffer ourselves
for(int i=0; i<w*h; i++)
- if ((data[i] & 0xFF000000) != 0xFF000000 && (data[i] & 0xFF000000) != 0x00)
+ if ((data[i] & 0xFF000000) == 0xFF000000)
+ needsStipple = true;
+ else if ((data[i] & 0xFF000000) != 0x00)
return;
- X11DoubleBuffer b = new X11DoubleBuffer(w, h);
+ buildDoubleBuffer(needsStipple);
+ }
+
+ void buildDoubleBuffer(boolean needsStipple) {
+ if (doublebuf != null) return;
+ // no point in using a shared pixmap since we'll only write to this image once
+ X11DoubleBuffer b = new X11DoubleBuffer(width, height, false);
b.drawPicture(this, 0, 0);
- b.createStipple(this);
+ if (needsStipple) b.createStipple(this);
doublebuf = b;
}
}
- // FIXME: finalizer to free X resources
+ /**
+ * An X11DoubleBuffer is implemented as an X11 pixmap. "Normal"
+ * DoubleBuffers will use XShm shared pixmaps if
+ * available. X11DoubleBuffers created to accelerate Pictures
+ * with all-or-nothing alpha will not use shared pixmaps, however
+ * (since they are only written to once.
+ */
public static class X11DoubleBuffer implements DoubleBuffer {
int clipx, clipy, clipw, cliph;
/** Sets the DoubleBuffer's internal stipple to the alpha==0x00 regions of xpi */
public native void createStipple(X11Picture xpi);
-
- static int old_shmsize = 0;
- static RawData shm_ximage;
- static int shmsegs = 0;
- int force_slowpath = 0;
- RawData mxi = null;
- int shared_pixmap = 0;
-
- boolean usePixmap = false;
- /** Pixmap (if any) representing this Picture */
- RawData pm;
+ RawData pm; // Pixmap (if any) representing this Picture
+ boolean shared_pixmap = false; // true if pm is a ShmPixmap
+ RawData fake_ximage = null; // a 'fake' XImage corresponding to the shared pixmap; gives us the address and depth parameters
+ RawData shm_segment = null; // XShmSegmentInfo
- /** Graphics Context on pm (never changes, so it's fast) */
- RawData gc;
-
- /** Graphics Context on pm, use this one if you need a clip/stipple */
- RawData clipped_gc;
+ RawData gc; // Graphics Context on pm (never changes, so it's fast)
+ RawData clipped_gc; // Graphics Context on pm, use this one if you need a clip/stipple
/** DoubleBuffer mode */
- public X11DoubleBuffer(int w, int h) {
+ public X11DoubleBuffer(int w, int h) { this(w, h, true); }
+ public X11DoubleBuffer(int w, int h, boolean shared_pixmap) {
width = clipw = w;
height = cliph = h;
clipx = clipy = 0;
- shared_pixmap = 1;
+ this.shared_pixmap = shared_pixmap;
natInit();
}
drawPicture(source, x, y, x + source.getWidth(), y + source.getHeight(), 0, 0, source.getWidth(), source.getHeight());
}
+ public void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
+ if (!(dx2 - dx1 != sx2 - sx1 || dy2 - dy1 != sy2 - sy1) && ((X11Picture)source).doublebuf != null)
+ fastDrawPicture(source, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+ else
+ slowDrawPicture(source, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+ }
+
+ /** fast path for image drawing (no scaling, all-or-nothing alpha) */
+ public native void fastDrawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
+
+ /** slow path for image drawing */
+ public native void slowDrawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
+
public int getWidth() { return width; }
public int getHeight() { return height; }
public native void natInit();
- public native void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
public native void fillRect(int x, int y, int x2, int y2, int color);
public native void drawString(String font, String text, int x, int y, int color);
+ public native void finalize();
}