/* * wview_x11.c - X11 view backend for WINGs * * Implements W_ViewBackend using Xlib calls. */ #include "WINGsP.h" #include "WINGs/WINGsX11.h" #include "wwindow_p.h" #include #include #include "../src/GNUstep.h" extern void W_X11PlatformInit(W_Screen *scr); static XContext ViewContext = 0; static void *x11_screen_init(W_Screen *scr) { if (ViewContext == 0) ViewContext = XUniqueContext(); return scr; /* no separate context needed; use scr as token */ } static void x11_screen_fini(void *vctx) { (void)vctx; } static void x11_create_root(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; /* Always use the real root window as parent for toplevel windows, * even when RContext->drawable is an intermediate window created * for a non-default visual. Otherwise MapRequest won't reach the * window manager (which selects SubstructureRedirect on root). */ view->window = RootWindow(scr->display, scr->screen); view->size.width = WidthOfScreen(ScreenOfDisplay(scr->display, scr->screen)); view->size.height = HeightOfScreen(ScreenOfDisplay(scr->display, scr->screen)); } static void x11_realize(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; Display *dpy = scr->display; Window parentWID = view->parent->window; /* Build XSetWindowAttributes from the backend-neutral W_View * attribs. W_View.attribs no longer has the X11 layout (so the * shared header can be Xlib-free); copy field-by-field here. */ XSetWindowAttributes xattribs; memset(&xattribs, 0, sizeof(xattribs)); xattribs.background_pixmap = view->attribs.background_pixmap; xattribs.background_pixel = view->attribs.background_pixel; xattribs.border_pixel = view->attribs.border_pixel; xattribs.colormap = view->attribs.colormap; xattribs.cursor = view->attribs.cursor; xattribs.override_redirect = view->attribs.override_redirect; xattribs.save_under = view->attribs.save_under; xattribs.event_mask = view->attribs.event_mask; xattribs.do_not_propagate_mask = view->attribs.do_not_propagate_mask; xattribs.bit_gravity = NorthWestGravity; xattribs.win_gravity = NorthWestGravity; xattribs.backing_store = NotUseful; view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y, view->size.width, view->size.height, 0, scr->depth, InputOutput, scr->visual, view->attribFlags, &xattribs); XSaveContext(dpy, view->window, ViewContext, (XPointer)view); } static void x11_map(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XMapRaised(scr->display, view->window); XFlush(scr->display); } static void x11_unmap(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XUnmapWindow(scr->display, view->window); XFlush(scr->display); } static void x11_map_subviews(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XMapSubwindows(scr->display, view->window); XFlush(scr->display); } static void x11_unmap_subviews(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XUnmapSubwindows(scr->display, view->window); XFlush(scr->display); } static void x11_move(void *vctx, W_View *view, int x, int y) { W_Screen *scr = (W_Screen *)vctx; XMoveWindow(scr->display, view->window, x, y); } static void x11_resize(void *vctx, W_View *view, unsigned int w, unsigned int h) { W_Screen *scr = (W_Screen *)vctx; XResizeWindow(scr->display, view->window, w, h); } static void x11_raise(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XRaiseWindow(scr->display, view->window); } static void x11_lower(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XLowerWindow(scr->display, view->window); } static void x11_reparent(void *vctx, W_View *view, W_View *newParent, int x, int y) { W_Screen *scr = (W_Screen *)vctx; XReparentWindow(scr->display, view->window, newParent->window, x, y); } static void x11_destroy(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XDeleteContext(scr->display, view->window, ViewContext); if (!view->flags.parentDying || view->flags.topLevel) XDestroyWindow(scr->display, view->window); } static void x11_set_background_color(void *vctx, W_View *view, WMColor *color) { W_Screen *scr = (W_Screen *)vctx; XSetWindowBackground(scr->display, view->window, W_PIXEL(color)); XClearWindow(scr->display, view->window); } static void x11_set_cursor(void *vctx, W_View *view, Cursor cursor) { W_Screen *scr = (W_Screen *)vctx; XDefineCursor(scr->display, view->window, cursor); } static void x11_redisplay(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XEvent xev; WMEvent ev; memset(&xev, 0, sizeof(xev)); xev.xexpose.type = Expose; xev.xexpose.display = scr->display; xev.xexpose.window = view->window; xev.xexpose.count = 0; xev.xexpose.serial = 0; memset(&ev, 0, sizeof(ev)); ev.type = WME_EXPOSE; ev.window = (WNativeWindow)view->window; ev.u.expose.window = (WNativeWindow)view->window; ev.u.expose.count = 0; ev._x11_raw = &xev; ev._view_target = view; WMHandleEvent(&ev); } static WMPoint x11_get_screen_position(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; Window foo; int x, y, topX, topY; unsigned int bar; W_View *topView; topView = view; while (topView->parent && topView->parent != scr->rootView) topView = topView->parent; if (!XGetGeometry(scr->display, topView->window, &foo, &topX, &topY, &bar, &bar, &bar, &bar)) { topX = topY = 0; } XTranslateCoordinates(scr->display, view->window, scr->rootWin, 0, 0, &x, &y, &foo); return wmkpoint(x - topX, y - topY); } W_View *W_GetViewForXWindow(Display *display, Window window) { W_View *view; if (ViewContext == 0) return NULL; if (XFindContext(display, window, ViewContext, (XPointer *)&view) == 0) return view; return NULL; } static Bool x11_selection_acquire(void *vctx, W_View *view, Atom selection, Time timestamp) { (void)vctx; Display *dpy = view->screen->display; XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp); return (XGetSelectionOwner(dpy, selection) == W_VIEW_DRAWABLE(view)); } static void x11_selection_release(void *vctx, W_View *view, Atom selection) { W_Screen *scr = (W_Screen *)vctx; Display *dpy = scr->display; Window win = W_VIEW_DRAWABLE(view); XGrabServer(dpy); if (XGetSelectionOwner(dpy, selection) == win) XSetSelectionOwner(dpy, selection, WM_NATIVE_NONE, WM_CURRENT_TIME); XUngrabServer(dpy); } static Bool x11_selection_request(void *vctx, W_View *view, Atom selection, Atom target, Time timestamp) { W_Screen *scr = (W_Screen *)vctx; Display *dpy = scr->display; if (XGetSelectionOwner(dpy, selection) == WM_NATIVE_NONE) return False; return XConvertSelection(dpy, selection, target, scr->clipboardAtom, W_VIEW_DRAWABLE(view), timestamp) != 0; } static void x11_clipboard_store(void *vctx, const char *text, int len) { W_Screen *scr = (W_Screen *)vctx; XStoreBuffer(scr->display, text, len, 0); } static char *x11_clipboard_fetch(void *vctx, int *len_out) { W_Screen *scr = (W_Screen *)vctx; int n = 0; char *xtext = XFetchBuffer(scr->display, &n, 0); if (!xtext || n <= 0) { if (len_out) *len_out = 0; return NULL; } char *copy = wmalloc(n + 1); memcpy(copy, xtext, n); copy[n] = '\0'; XFree(xtext); if (len_out) *len_out = n; return copy; } static void x11_pointer_grab(void *vctx, W_View *view, int owner_events, unsigned long time) { W_Screen *scr = (W_Screen *)vctx; XGrabPointer(scr->display, view->window, owner_events, WM_EVMASK_BUTTON_RELEASE | WM_EVMASK_BUTTON_MOTION | WM_EVMASK_ENTER_WINDOW | WM_EVMASK_LEAVE_WINDOW, WM_GRAB_MODE_ASYNC, WM_GRAB_MODE_ASYNC, WM_NATIVE_NONE, WM_NATIVE_NONE, time); } static void x11_pointer_ungrab(void *vctx, unsigned long time) { W_Screen *scr = (W_Screen *)vctx; XUngrabPointer(scr->display, time); } static void x11_bell(void *vctx) { W_Screen *scr = (W_Screen *)vctx; XBell(scr->display, 0); } static Atom XA_Targets = WM_NATIVE_NONE; static Atom XA_Format_Text = WM_NATIVE_NONE; static Atom XA_Format_Compound_Text = WM_NATIVE_NONE; static void x11_text_init(void *vctx, W_View *view, void *stipple_gc_out) { W_Screen *scr = (W_Screen *)vctx; Display *dpy = scr->display; GC *gc_out = (GC *)stipple_gc_out; XGCValues gcv; if (XA_Targets == WM_NATIVE_NONE) { XA_Targets = XInternAtom(dpy, "TARGETS", False); XA_Format_Text = XInternAtom(dpy, "TEXT", False); XA_Format_Compound_Text = XInternAtom(dpy, "COMPOUND_TEXT", False); } gcv.graphics_exposures = False; gcv.foreground = W_PIXEL(scr->gray); gcv.background = W_PIXEL(scr->darkGray); gcv.fill_style = FillStippled; gcv.stipple = XCreateBitmapFromData(dpy, W_DRAWABLE(scr), "\xaa\x55\xaa\x55\xaa\x55\xaa\x55", 8, 8); *gc_out = XCreateGC(dpy, W_DRAWABLE(scr), GCForeground | GCBackground | GCStipple | GCFillStyle | GCGraphicsExposures, &gcv); } static void x11_balloon_draw(void *vctx, W_View *view, int x, int y, int w, int h, const char *text) { W_Screen *scr = (W_Screen *)vctx; (void)scr; extern void W_BalloonShowText(void *bPtr, int x, int y, int w, int h, const char *text); W_BalloonShowText(view->screen->balloon, x, y, w, h, text); } static void x11_flush(void *vctx) { W_Screen *scr = (W_Screen *)vctx; XFlush(scr->display); } static void x11_window_set_title(void *vctx, W_View *view, const char *title) { W_Screen *scr = (W_Screen *)vctx; XTextProperty property; int result; result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property); if (result == XNoMemory || result == XLocaleNotSupported) { XStoreName(scr->display, view->window, title); } else { XSetWMName(scr->display, view->window, &property); if (property.value) XFree(property.value); } XChangeProperty(scr->display, view->window, scr->netwmName, scr->utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title)); } static void x11_window_set_icon_title(void *vctx, W_View *view, const char *title) { W_Screen *scr = (W_Screen *)vctx; XTextProperty property; int result; result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property); if (result == XNoMemory || result == XLocaleNotSupported) { XSetIconName(scr->display, view->window, title); } else { XSetWMIconName(scr->display, view->window, &property); if (property.value) XFree(property.value); } XChangeProperty(scr->display, view->window, scr->netwmIconName, scr->utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title)); } static void x11_window_set_icon_image(void *vctx, W_View *view, RImage *image) { W_Screen *scr = (W_Screen *)vctx; unsigned long *data; int x, y, o; if (!image) return; data = wmalloc((image->width * image->height + 2) * sizeof(long)); o = 0; data[o++] = image->width; data[o++] = image->height; for (y = 0; y < image->height; y++) { for (x = 0; x < image->width; x++) { unsigned long pixel; int offs = (x + y * image->width); if (image->format == RRGBFormat) { pixel = ((unsigned long) image->data[offs * 3 ]) << 16; pixel |= ((unsigned long) image->data[offs * 3 + 1]) << 8; pixel |= ((unsigned long) image->data[offs * 3 + 2]); } else { pixel = ((unsigned long) image->data[offs * 4 ]) << 16; pixel |= ((unsigned long) image->data[offs * 4 + 1]) << 8; pixel |= ((unsigned long) image->data[offs * 4 + 2]); pixel |= ((unsigned long) image->data[offs * 4 + 3]) << 24; } data[o++] = pixel; } } XChangeProperty(scr->display, view->window, scr->netwmIcon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, (image->width * image->height + 2)); wfree(data); } static void x11_writeGNUstepWMAttr(W_Screen *scr, Window window, GNUstepWMAttributes *attr) { unsigned long data[9]; data[0] = attr->flags; data[1] = attr->window_style; data[2] = attr->window_level; data[3] = 0; data[4] = attr->miniaturize_pixmap; data[5] = attr->close_pixmap; data[6] = attr->miniaturize_mask; data[7] = attr->close_mask; data[8] = attr->extra_flags; XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom, 32, PropModeReplace, (unsigned char *)data, 9); } static void x11_window_realize(void *vctx, W_View *view, const char *name, const char *class, W_View *owner) { W_Screen *scr = (W_Screen *)vctx; _Window *win = (_Window *)view->self; XWMHints *hints; XClassHint *classHint; Atom atoms[4]; int count; GNUstepWMAttributes attribs; classHint = XAllocClassHint(); classHint->res_name = (char *)name; classHint->res_class = (char *)class; XSetClassHint(scr->display, view->window, classHint); XFree(classHint); hints = XAllocWMHints(); hints->flags = 0; if (!scr->aflags.simpleApplication) { hints->flags |= WindowGroupHint; hints->window_group = scr->groupLeader; } if (win->miniImage) { hints->flags |= IconPixmapHint; hints->icon_pixmap = WMGetPixmapXID(win->miniImage); hints->icon_mask = WMGetPixmapMaskXID(win->miniImage); if (hints->icon_mask != WM_NATIVE_NONE) { hints->flags |= IconMaskHint; } } if (hints->flags != 0) XSetWMHints(scr->display, view->window, hints); XFree(hints); count = 0; if (win->closeAction) atoms[count++] = scr->deleteWindowAtom; if (count > 0) XSetWMProtocols(scr->display, view->window, atoms, count); if (win->title || win->miniTitle) XmbSetWMProperties(scr->display, view->window, win->title, win->miniTitle, NULL, 0, NULL, NULL, NULL); /* GNUstep/Window Maker attributes */ memset(&attribs, 0, sizeof(GNUstepWMAttributes)); attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr; if (win->minSize.width == win->maxSize.width && win->minSize.height == win->maxSize.height) win->flags.style &= ~WMResizableWindowMask; attribs.window_style = win->flags.style; attribs.window_level = win->level; attribs.extra_flags = win->flags.documentEdited ? GSDocumentEditedFlag : 0; x11_writeGNUstepWMAttr(scr, view->window, &attribs); if (owner) XSetTransientForHint(scr->display, view->window, owner->window); if (win->title) x11_window_set_title(vctx, view, win->title); } static void x11_window_set_geometry(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; _Window *win = (_Window *)view->self; XSizeHints *hints; hints = XAllocSizeHints(); if (!hints) return; hints->flags = 0; if (win->flags.setPPos) { hints->flags |= PPosition; hints->x = win->ppos.x; hints->y = win->ppos.y; } if (win->flags.setUPos) { hints->flags |= USPosition; hints->x = win->upos.x; hints->y = win->upos.y; } if (win->minSize.width > 0 && win->minSize.height > 0) { hints->flags |= PMinSize; hints->min_width = win->minSize.width; hints->min_height = win->minSize.height; } if (win->maxSize.width > 0 && win->maxSize.height > 0) { hints->flags |= PMaxSize; hints->max_width = win->maxSize.width; hints->max_height = win->maxSize.height; } if (win->baseSize.width > 0 && win->baseSize.height > 0) { hints->flags |= PBaseSize; hints->base_width = win->baseSize.width; hints->base_height = win->baseSize.height; } if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) { hints->flags |= PResizeInc; hints->width_inc = win->resizeIncrement.width; hints->height_inc = win->resizeIncrement.height; } if (win->flags.setAspect) { hints->flags |= PAspect; hints->min_aspect.x = win->minAspect.x; hints->min_aspect.y = win->minAspect.y; hints->max_aspect.x = win->maxAspect.x; hints->max_aspect.y = win->maxAspect.y; } if (hints->flags) XSetWMNormalHints(scr->display, view->window, hints); XFree(hints); } static void x11_window_withdraw(void *vctx, W_View *view) { W_Screen *scr = (W_Screen *)vctx; XWithdrawWindow(scr->display, view->window, scr->screen); } static void x11_xor_fill_rect(void *vctx, W_View *view, int x, int y, int w, int h) { W_Screen *scr = (W_Screen *)vctx; XFillRectangle(scr->display, view->window, scr->ixorGC, x, y, w, h); } const W_ViewBackend W_ViewBackendX11 = { .screen_init = x11_screen_init, .screen_fini = x11_screen_fini, .create_root = x11_create_root, .realize = x11_realize, .map = x11_map, .unmap = x11_unmap, .map_subviews = x11_map_subviews, .unmap_subviews = x11_unmap_subviews, .move = x11_move, .resize = x11_resize, .raise = x11_raise, .lower = x11_lower, .reparent = x11_reparent, .destroy = x11_destroy, .set_background_color = x11_set_background_color, .set_cursor = x11_set_cursor, .redisplay = x11_redisplay, .get_screen_position = x11_get_screen_position, .selection_acquire = x11_selection_acquire, .selection_release = x11_selection_release, .selection_request = x11_selection_request, .selection_fetch = NULL, .platform_init = W_X11PlatformInit, .flush = x11_flush, .clipboard_store = x11_clipboard_store, .clipboard_fetch = x11_clipboard_fetch, .drag_begin = NULL, .window_set_title = x11_window_set_title, .window_set_icon_title = x11_window_set_icon_title, .window_set_icon_image = x11_window_set_icon_image, .window_realize = x11_window_realize, .window_set_geometry = x11_window_set_geometry, .window_withdraw = x11_window_withdraw, .pointer_grab = x11_pointer_grab, .pointer_ungrab = x11_pointer_ungrab, .bell = x11_bell, .balloon_draw = x11_balloon_draw, .text_init = x11_text_init, .xor_fill_rect = x11_xor_fill_rect, .magnify_callback = W_ColorPanelMagnify, };