#include "config.h" #include #include #include #include #include #include #include #include #include #include "_stdint.h" #include "xatoms.h" #include "x11.h" #include "defaults.h" #include "colors.h" #include "proto.h" #include "panic.h" int window_init(struct conn *conn, struct win *w, struct win *ow, int nscreen); struct conn *conn; struct win win; static char *opt_display; static char *opt_geometry; static char *opt_class = "Seven"; static char *opt_title = "seven"; static char *opt_font; static int opt_sync; static int opt_withdrawn; static int saved_argc; static const char **saved_argv; const struct poptOption x11_options[] = { {"display", 0, POPT_ARG_STRING, &opt_display, 0, "which X11 display to connect to", "localhost:0.0" }, {"geometry", 'g', POPT_ARG_STRING, &opt_geometry, 0, "X geometry specification", "GEOMETRY" }, {"sync", 0, POPT_ARG_NONE, &opt_sync, 0, "Make X calls synchronous", NULL}, {"title", 'T', POPT_ARG_STRING, &opt_title, 0, "Set Window title displayed by window manager", "TITLE" }, {"class", 0, POPT_ARG_STRING, &opt_class, 0, "X class property", "CLASS" }, {"withdrawn", 0, POPT_ARG_NONE, &opt_withdrawn, 0, "Start hidden from view if supported by your window manager", NULL }, {"font", 0, POPT_ARG_STRING, &opt_font, 0, "Which font to use.", "FONT"}, POPT_TABLEEND }; static void free_fonts(struct conn *conn) { for(int i = 0; i < ScreenCount(conn->dpy); i++) { for(int j = 0; j < FS_MAX; j ++) for(int k = 0; k < conn->fs[i].fonts[j].number; k++) { XftFontClose(conn->dpy, conn->fs[i].fonts[j].fonts[k]); } } } struct font* get_font(struct conn *conn, int screen, int type) { FcFontSet *fs; if(!conn->fs[screen].fonts[type].fonts) { FcPattern *p = XftNameParse(opt_font ? opt_font : D_font); if(type & FS_BOLD) FcPatternAddInteger(p, FC_WEIGHT, FC_WEIGHT_BOLD); if(type & FS_ITALIC) FcPatternAddInteger(p, FC_SLANT, FC_SLANT_ITALIC); //FcDefaultSubstitute(p); FcConfigSubstitute(0, p, FcMatchPattern); XftDefaultSubstitute(conn->dpy, screen, p); //p = XftFontMatch(conn->dpy, screen, p, NULL); //FcPatternPrint(p); //FcPattern *p = conn->pattern; fs = FcFontSort(NULL, p, true, 0, NULL); conn->fs[screen].fonts[type].number = fs->nfont; conn->fs[screen].fonts[type].fonts = malloc(sizeof(XftFont *)*fs->nfont); for(int i = 0; i < fs->nfont; i++) conn->fs[screen].fonts[type].fonts[i] = XftFontOpenPattern(conn->dpy,FcFontRenderPrepare(NULL, conn->pattern, fs->fonts[i])); //FcFontSetDestroy(fs); } return &conn->fs[screen].fonts[type]; } void font_lookup_char(struct conn *conn, wchar_t ch, int screen, int type, XftFont **font) { struct font *f = get_font(conn, screen, type); for(int i = 0; i < f->number; i++) { if(FcCharSetHasChar(f->fonts[i]->charset, ch)) { *font = f->fonts[i]; return; } } *font = NULL; } void x11_detach(void) { if(!conn) return; free_fonts(conn); FcPatternDestroy(conn->pattern); XSync(conn->dpy, true); XCloseDisplay(conn->dpy); conn->dpy = NULL; conn = NULL; memset(&win,0,sizeof(struct win)); } void x11_get_info(struct x11_info *x) { x->xauthority = (getenv("XAUTHORITY")); if(conn) { x->xwindow = win.w; x->display = DisplayString(conn->dpy); x->server_vendor = ServerVendor(conn->dpy); } else { x->server_vendor = ""; x->xwindow = 0; x->display = XDisplayName(opt_display); } } void x11_attach(struct x11_info *x) { assert(!conn); conn = malloc(sizeof(struct conn)); if((conn->dpy=XOpenDisplay(x->display)) == NULL) { fprintf(stderr,"X11 says \"I can't open display: %s\"\n", XDisplayName(x->display)); exit(2); } if(fcntl(ConnectionNumber(conn->dpy), F_SETFD, 1) == -1) panicno("X11 Socket"); XSynchronize(conn->dpy, opt_sync); setup_defaults(conn->dpy, "seven"); defaults_finalize(); intern_xatoms(conn->dpy); realloc_colors(conn->dpy, DefaultColormap(conn->dpy, DefaultScreen(conn->dpy))); conn->fs = calloc(sizeof(struct fontset), ScreenCount(conn->dpy)); //conn->pattern = FcNameParse(D_font); conn->pattern = XftNameParse(opt_font ? opt_font : D_font); FcDefaultSubstitute(conn->pattern); window_init(conn,&win, NULL, -1); char *startup_id = getenv("DESKTOP_STARTUP_ID"); if(startup_id) { char *time_str = strstr(startup_id, "_TIME"); if(time_str != NULL) { errno = 0; time_str += 5; char *end; unsigned long retval = strtoul(time_str, &end, 0); if (end != time_str && errno == 0) XChangeProperty(conn->dpy, win.w, XA__NET_WM_USER_TIME, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&retval, 1); } XChangeProperty(conn->dpy, win.w, XA__NET_STARTUP_ID, XA_UTF8_STRING, 8, PropModeReplace, (unsigned char *)startup_id, strlen(startup_id)); unsetenv("DESKTOP_STARTUP_ID"); } printf("connected to %s\n", DisplayString(conn->dpy)); } void window_fini(struct win *w) { XDestroyWindow(conn->dpy, w->w); } int window_init(struct conn *conn, struct win *w, struct win *ow, int nscreen) { XClassHint *xch; XWMHints *hints; XSizeHints *shints; uint32_t pid; Screen *screen; switch(nscreen) { case -1: nscreen = DefaultScreen(conn->dpy); break; case -2: if(ow) nscreen = (ow->current_screen + 1) % ScreenCount(conn->dpy); else nscreen = DefaultScreen(conn->dpy); break; default: if(nscreen < 0 || nscreen >= ScreenCount(conn->dpy)) nscreen = DefaultScreen(conn->dpy); break; } w->current_screen = nscreen; screen = ScreenOfDisplay(conn->dpy, nscreen); unsigned long valuemask = CWEventMask | CWBitGravity | CWBorderPixel; w->att.event_mask = KeyPressMask|ExposureMask|StructureNotifyMask|VisibilityChangeMask|ButtonPressMask|PropertyChangeMask; w->att.bit_gravity = StaticGravity; w->att.border_pixel = DC_borderColor->pixel; shints = XAllocSizeHints(); int fw,fh; w->fn = XftFontOpenName(conn->dpy, nscreen, opt_font ? opt_font : D_font); get_charcell_size(&fw, &fh); shints->width_inc = fw; shints->height_inc = fh; shints->flags = PResizeInc; int x_ret = 0,y_ret = 0,grav_ret; if (ow) { w->width = ow->width; w->height = ow->height; } else { XWMGeometry(conn->dpy,nscreen,opt_geometry,D_geometry, DI_borderWidth, shints, &x_ret,&y_ret,&w->width,&w->height,&grav_ret); } w->w = XCreateWindow(conn->dpy,RootWindowOfScreen(screen),x_ret,y_ret, w->width, w->height, DI_borderWidth, DefaultDepth(conn->dpy, nscreen), InputOutput, DefaultVisual(conn->dpy, nscreen), valuemask, &w->att); w->gc = XCreateGC(conn->dpy, w->w, 0, NULL ); XSetGraphicsExposures(conn->dpy, w->gc, 0); w->xftdraw = XftDrawCreate(conn->dpy, w->w, DefaultVisual(conn->dpy,nscreen), DefaultColormap(conn->dpy,nscreen)); //XSetWindowBackgroundPixmap(conn->dpy, w->w, None); XSetWindowBackground(conn->dpy, w->w, DC_background->pixel); xch = XAllocClassHint(); xch->res_name = NULL; xch->res_class = opt_class; hints = XAllocWMHints(); hints->window_group = w->w; hints->input = true; hints->flags = WindowGroupHint | StateHint | InputHint; if (opt_withdrawn && !ow) hints->initial_state = WithdrawnState; else hints->initial_state = NormalState; XmbSetWMProperties(conn->dpy, w->w, opt_title, D_iconName, (char **)saved_argv, saved_argc, shints, hints, xch); XFree(xch); XFree(hints); XFree(shints); pid = getpid(); XChangeProperty(conn->dpy, w->w, XA__NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); // Atom protocols[] = { XA_WM_DELETE_WINDOW, XA__NET_WM_SYNC_REQUEST }; Atom protocols[] = { XA_WM_DELETE_WINDOW, XA__NET_WM_PING, XA__NET_WM_SYNC_REQUEST }; XSetWMProtocols(conn->dpy,w->w,protocols,sizeof(protocols)/sizeof(Atom)); XSyncValue v; XSyncIntToValue(&v, 42); win.syncCounter = XSyncCreateCounter(conn->dpy, v); XSyncIntToValue(&win.syncValue,0); XChangeProperty(conn->dpy, win.w, XA__NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&win.syncCounter, 1); return 0; } void x11_switchscreen(int nscreen) { struct win w; if(!IS_ATTACHED() || nscreen == win.current_screen) return; window_init(conn, &w, &win, nscreen); window_fini(&win); //XMapWindow(conn->dpy, w.w); win = w; } void x11_init(int argc, char *argv[]) { saved_argc = argc; saved_argv = (const char **)argv; } void x11_close(void) { XCloseDisplay(conn->dpy); } void get_charcell_size(int *width, int *height) { XGlyphInfo gi; FcChar32 ch = 'm'; XftTextExtents32(conn->dpy, win.fn, &ch, 1, &gi); *width = gi.width; *height = gi.height; //*width = win.fn->max_advance_width; //*height = win.fn->height; *height = win.fn->ascent + win.fn->descent; }