/** Send a JWM message to the root window. */ void SendJWMMessage(const char *message) { XEvent event; OpenConnection(); memset(&event, 0, sizeof(event)); event.xclient.type = ClientMessage; event.xclient.window = rootWindow; event.xclient.message_type = JXInternAtom(display, message, False); event.xclient.format = 32; JXSendEvent(display, rootWindow, False, SubstructureRedirectMask, &event); CloseConnection(); }
/** Startup the dock. */ void StartupDock(void) { char *selectionName; if(!dock) { /* No dock has been requested. */ return; } if(dock->window == None) { /* No dock yet. */ /* Get the selection atom. */ selectionName = AllocateStack(sizeof(BASE_SELECTION_NAME)); snprintf(selectionName, sizeof(BASE_SELECTION_NAME), BASE_SELECTION_NAME, rootScreen); dockAtom = JXInternAtom(display, selectionName, False); ReleaseStack(selectionName); /* The location and size of the window doesn't matter here. */ dock->window = JXCreateSimpleWindow(display, rootWindow, /* x, y, width, height */ 0, 0, 1, 1, /* border_size, border_color */ 0, 0, /* background */ colors[COLOR_TRAY_BG2]); JXSelectInput(display, dock->window, SubstructureNotifyMask | SubstructureRedirectMask | EnterWindowMask | PointerMotionMask | PointerMotionHintMask); } dock->cp->window = dock->window; }
/** Set root hints and intern atoms. */ void StartupHints(void) { unsigned long *array; char *data; Atom *supported; Window win; unsigned int x; unsigned int count; /* Determine how much space we will need on the stack and allocate it. */ count = 0; for(x = 0; x < settings.desktopCount; x++) { count += strlen(GetDesktopName(x)) + 1; } if(count < 2 * sizeof(unsigned long)) { count = 2 * sizeof(unsigned long); } if(count < ATOM_COUNT * sizeof(Atom)) { count = ATOM_COUNT * sizeof(Atom); } data = AllocateStack(count); array = (unsigned long*)data; supported = (Atom*)data; /* Intern the atoms */ for(x = 0; x < ATOM_COUNT; x++) { *atomList[x].atom = JXInternAtom(display, atomList[x].name, False); } /* _NET_SUPPORTED */ for(x = FIRST_NET_ATOM; x <= LAST_NET_ATOM; x++) { supported[x - FIRST_NET_ATOM] = atoms[x]; } JXChangeProperty(display, rootWindow, atoms[ATOM_NET_SUPPORTED], XA_ATOM, 32, PropModeReplace, (unsigned char*)supported, LAST_NET_ATOM - FIRST_NET_ATOM + 1); /* _NET_NUMBER_OF_DESKTOPS */ SetCardinalAtom(rootWindow, ATOM_NET_NUMBER_OF_DESKTOPS, settings.desktopCount); /* _NET_DESKTOP_NAMES */ count = 0; for(x = 0; x < settings.desktopCount; x++) { const char *name = GetDesktopName(x); const unsigned len = strlen(name); memcpy(&data[count], name, len + 1); count += len + 1; } JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_NAMES], atoms[ATOM_UTF8_STRING], 8, PropModeReplace, (unsigned char*)data, count); /* _NET_DESKTOP_GEOMETRY */ array[0] = rootWidth; array[1] = rootHeight; JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_GEOMETRY], XA_CARDINAL, 32, PropModeReplace, (unsigned char*)array, 2); /* _NET_DESKTOP_VIEWPORT */ array[0] = 0; array[1] = 0; JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_VIEWPORT], XA_CARDINAL, 32, PropModeReplace, (unsigned char*)array, 2); /* _NET_WM_NAME */ win = supportingWindow; JXChangeProperty(display, win, atoms[ATOM_NET_WM_NAME], atoms[ATOM_UTF8_STRING], 8, PropModeReplace, (unsigned char*)"JWM", 3); /* _NET_WM_PID */ array[0] = getpid(); JXChangeProperty(display, win, atoms[ATOM_NET_WM_PID], XA_CARDINAL, 32, PropModeReplace, (unsigned char*)array, 1); /* _NET_SUPPORTING_WM_CHECK */ SetWindowAtom(rootWindow, ATOM_NET_SUPPORTING_WM_CHECK, win); SetWindowAtom(win, ATOM_NET_SUPPORTING_WM_CHECK, win); ReleaseStack(data); }
/** Prepare the connection. */ void StartupConnection(void) { XSetWindowAttributes attr; #ifdef USE_SHAPE int shapeError; #endif #ifdef USE_XRENDER int renderEvent; int renderError; #endif struct sigaction sa; char name[32]; Window win; XEvent event; int revert; initializing = 1; OpenConnection(); #if 0 XSynchronize(display, True); #endif /* Create the supporting window used to verify JWM is running. */ supportingWindow = JXCreateSimpleWindow(display, rootWindow, 0, 0, 1, 1, 0, 0, 0); /* Get the atom used for the window manager selection. */ snprintf(name, 32, "WM_S%d", rootScreen); managerSelection = JXInternAtom(display, name, False); /* Get the current window manager and take the selection. */ GrabServer(); win = JXGetSelectionOwner(display, managerSelection); if(win != None) { JXSelectInput(display, win, StructureNotifyMask); } JXSetSelectionOwner(display, managerSelection, supportingWindow, CurrentTime); UngrabServer(); /* Wait for the current selection owner to give up the selection. */ if(win != None) { /* Note that we need to wait for the current selection owner * to exit before we can expect to select SubstructureRedirectMask. */ XIfEvent(display, &event, SelectionReleased, (XPointer)&win); JXSync(display, False); } event.xclient.display = display; event.xclient.type = ClientMessage; event.xclient.window = rootWindow; event.xclient.message_type = JXInternAtom(display, managerProperty, False); event.xclient.format = 32; event.xclient.data.l[0] = CurrentTime; event.xclient.data.l[1] = managerSelection; event.xclient.data.l[2] = supportingWindow; event.xclient.data.l[3] = 2; event.xclient.data.l[4] = 0; JXSendEvent(display, rootWindow, False, StructureNotifyMask, &event); JXSync(display, False); JXSetErrorHandler(ErrorHandler); clientContext = XUniqueContext(); frameContext = XUniqueContext(); /* Set the events we want for the root window. * Note that asking for SubstructureRedirect will fail * if another window manager is already running. */ attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask | PropertyChangeMask | ColormapChangeMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask; JXChangeWindowAttributes(display, rootWindow, CWEventMask, &attr); memset(&sa, 0, sizeof(sa)); sa.sa_flags = 0; sa.sa_handler = HandleExit; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sa.sa_flags = SA_NOCLDWAIT; sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, NULL); #ifdef USE_SHAPE haveShape = JXShapeQueryExtension(display, &shapeEvent, &shapeError); if (haveShape) { Debug("shape extension enabled"); } else { Debug("shape extension disabled"); } #endif #ifdef USE_XRENDER haveRender = JXRenderQueryExtension(display, &renderEvent, &renderError); if(haveRender) { Debug("render extension enabled"); } else { Debug("render extension disabled"); } #endif /* Make sure we have input focus. */ win = None; JXGetInputFocus(display, &win, &revert); if(win == None) { JXSetInputFocus(display, rootWindow, RevertToParent, CurrentTime); } initializing = 0; }
/** Startup trays. */ void StartupTray(void) { XSetWindowAttributes attr; Atom atom; unsigned long attrMask; TrayType *tp; TrayComponentType *cp; int variableSize; int variableRemainder; int width, height; int xoffset, yoffset; for(tp = trays; tp; tp = tp->next) { LayoutTray(tp, &variableSize, &variableRemainder); /* Create the tray window. */ /* The window is created larger for a border. */ attrMask = CWOverrideRedirect; attr.override_redirect = True; /* We can't use PointerMotionHintMask since the exact position * of the mouse on the tray is important for popups. */ attrMask |= CWEventMask; attr.event_mask = ButtonPressMask | ButtonReleaseMask | SubstructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | PointerMotionMask; attrMask |= CWBackPixel; attr.background_pixel = colors[COLOR_TRAY_BG2]; attrMask |= CWBorderPixel; attr.border_pixel = colors[COLOR_TRAY_OUTLINE]; Assert(tp->width > 0); Assert(tp->height > 0); tp->window = JXCreateWindow(display, rootWindow, tp->x, tp->y, tp->width, tp->height, TRAY_BORDER_SIZE, rootVisual.depth, InputOutput, rootVisual.visual, attrMask, &attr); if(settings.trayOpacity < UINT_MAX) { /* Can't use atoms yet as it hasn't been initialized. */ atom = JXInternAtom(display, opacityAtom, False); JXChangeProperty(display, tp->window, atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&settings.trayOpacity, 1); } SetDefaultCursor(tp->window); /* Create and layout items on the tray. */ xoffset = 0; yoffset = 0; for(cp = tp->components; cp; cp = cp->next) { if(cp->Create) { if(tp->layout == LAYOUT_HORIZONTAL) { height = tp->height; width = cp->width; if(width == 0) { width = variableSize; if(variableRemainder) { width += 1; variableRemainder -= 1; } } } else { width = tp->width; height = cp->height; if(height == 0) { height = variableSize; if(variableRemainder) { height += 1; variableRemainder -= 1; } } } cp->width = Max(1, width); cp->height = Max(1, height); (cp->Create)(cp); } cp->x = xoffset; cp->y = yoffset; cp->screenx = tp->x + xoffset; cp->screeny = tp->y + yoffset; if(cp->window != None) { JXReparentWindow(display, cp->window, tp->window, xoffset, yoffset); } if(tp->layout == LAYOUT_HORIZONTAL) { xoffset += cp->width; } else { yoffset += cp->height; } } /* Show the tray. */ JXMapWindow(display, tp->window); trayCount += 1; } RequirePagerUpdate(); RequireTaskUpdate(); }
/** Startup trays. */ void StartupTray() { XSetWindowAttributes attr; Atom opacityAtom; unsigned long attrMask; TrayType *tp; TrayComponentType *cp; int variableSize; int variableRemainder; int width, height; int xoffset, yoffset; for(tp = trays; tp; tp = tp->next) { LayoutTray(tp, &variableSize, &variableRemainder); /* Create the tray window. */ /* The window is created larger for a border. */ attrMask = CWOverrideRedirect; attr.override_redirect = True; /* We can't use PointerMotionHintMask since the exact position * of the mouse on the tray is important for popups. */ attrMask |= CWEventMask; attr.event_mask = ButtonPressMask | ButtonReleaseMask | SubstructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | PointerMotionMask; attrMask |= CWBackPixel; attr.background_pixel = colors[COLOR_TRAY_BG]; tp->window = JXCreateWindow(display, rootWindow, tp->x, tp->y, tp->width, tp->height, 0, rootDepth, InputOutput, rootVisual, attrMask, &attr); if(trayOpacity < UINT_MAX) { /* Can't use atoms yet as it hasn't been initialized. */ opacityAtom = JXInternAtom(display, "_NET_WM_WINDOW_OPACITY", False); JXChangeProperty(display, tp->window, opacityAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&trayOpacity, 1); JXSync(display, False); } SetDefaultCursor(tp->window); /* Create and layout items on the tray. */ xoffset = tp->border; yoffset = tp->border; for(cp = tp->components; cp; cp = cp->next) { if(cp->Create) { if(tp->layout == LAYOUT_HORIZONTAL) { height = tp->height - 2 * tp->border; width = cp->width; if(width == 0) { width = variableSize; if(variableRemainder) { ++width; --variableRemainder; } } } else { width = tp->width - 2 * tp->border; height = cp->height; if(height == 0) { height = variableSize; if(variableRemainder) { ++height; --variableRemainder; } } } cp->width = width; cp->height = height; (cp->Create)(cp); } cp->x = xoffset; cp->y = yoffset; cp->screenx = tp->x + xoffset; cp->screeny = tp->y + yoffset; if(cp->window != None) { JXReparentWindow(display, cp->window, tp->window, xoffset, yoffset); } if(tp->layout == LAYOUT_HORIZONTAL) { xoffset += cp->width; } else { yoffset += cp->height; } } /* Show the tray. */ JXMapWindow(display, tp->window); ++trayCount; } UpdatePager(); UpdateTaskBar(); }