/* This is free software. See LICENSE for terms. * Copyright 2004 - 2015, Patricia Kirk. */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <netinet/in.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/mount.h> #include <netdb.h> #include <sys/stat.h> #include <math.h> #if defined (__linux__) #include <sys/time.h> #include <signal.h> #endif #include "proto.h" extern struct global g; extern struct pixstack *iconpix, *mainpix; extern char **args; Pixmap icondraw, iconmask, maindraw, mainmask; Display *maindisplay=0; Window rootwindow, iconwindow, mainwindow; Atom wmdeletewindow, wmprotocols; GC icongc, maingc; int mainscreen, colordepth; #if WITH_REMEXEC || WITH_TIMESYNC /* Check the execute and timesync sockets for * pending requests for service. execute is * a call to launch a salmon process, timesync * is a request for the current time if this * machine is the server. */ void checkSocket() { struct sockaddr_in sockaddr; socklen_t socklen=sizeof(struct sockaddr); int sock=-1; char buff[BUFPLUS], buffer[BUFPLUS]; #if WITH_TIMESYNC struct timeval tv; fd_set ready; const char *request="syncreq"; if (g.timeserver && g.timesock > 0) { /* If this host is the time server, hostname == timehost, * respond to requests for the time with the current time * of day as "tv_sec tv_usec". */ FD_ZERO(&ready); FD_SET(g.timesock, &ready); tv.tv_sec = tv.tv_usec = 0; select(g.timesock + 1, &ready, 0, 0, &tv); if (FD_ISSET(g.timesock, &ready) && (sock = accept(g.timesock, (struct sockaddr *)&sockaddr, &socklen)) > 0) { getnameinfo((struct sockaddr *)&sockaddr, socklen, buff, sizeof(buff), NULL, 0, 0); if (g.timelog) { snprintf(buffer, sizeof(buffer), "time sync request from %s", buff); logMessage(buffer); } if (strstr(buff, g.network)) { bzero(&buffer, sizeof(buffer)); read(sock, buffer, sizeof(buffer)); buffer[sizeof(buffer) - 1] = '\0'; if (strlen(buffer) && strstr(buffer, request) == buffer) { if (!(gettimeofday(&tv, NULL))) snprintf(buffer, sizeof(buffer), "%d %06d", (int)tv.tv_sec, (int)tv.tv_usec); else bzero(&buffer, sizeof(buffer)); send(sock, buffer, strlen(buffer), 256); } } shutdown(sock, SHUT_RDWR); close(sock); } } #endif /* WITH_TIMESYNC */ #if WITH_REMEXEC if (g.execsock > 0) { /* Respond to requests to launch new salmon processes * on localhost. These may be displayed locally or * on a remote host. Restrict responses to the LAN. */ if ((sock = accept(g.execsock, (struct sockaddr *)&sockaddr, &socklen)) > 0) { getnameinfo((struct sockaddr *)&sockaddr, socklen, buff, sizeof(buff), NULL, 0, 0); if (g.execlog) { snprintf(buffer, sizeof(buffer), "remote execute request from %s", buff); logMessage(buffer); } bzero(&buffer, sizeof(buffer)); if (strstr(buff, g.network)) { read(sock, buffer, sizeof(buffer)); buffer[sizeof(buffer) - 1] = '\0'; } shutdown(sock, SHUT_RDWR); close(sock); if (strlen(buffer) && !strncmp(buffer, "salmon ", 7)) { execComm(buffer); if (g.execstop) gdayMate(NULL, NULL); } } sock = -1; listen(g.execsock, 1); } #endif /* WITH_REMEXEC */ #if WITH_CONTROL if (g.ctlport) checkCtl(); #endif /* WITH_CONTROL */ } #endif /* WITH_REMEXEC || WITH_TIMESYNC */ /* This is only called when salmon * is sent to an inactive display. */ void checkFunc() { static int count=0; if (g.daemonize) { /* In some OS/X11 cases this routine is a memory leak that * can become serious after a few hours. If the process * is a child, exiting after five minutes launches a new * child and keeps the leak to a minimum. */ count++; if (count >= 300) gdayMate(NULL, NULL); } #if WITH_REMEXEC || WITH_TIMESYNC /* Check for execute and syncreq calls. */ checkSocket(); if (g.timeport && !g.timeserver) checkSync(); #endif /* WITH_REMEXEC || WITH_TIMESYNC */ #if WITH_CONTROL if (g.ctlport) checkCtl(); #endif /* WITH_CONTROL */ } void initWindow(int argc, char **argv) { XGCValues icongcv, maingcv; XSizeHints sizehints; XTextProperty title; XClassHint classhint; XWMHints wmhints; Pixel backpix, forepix; int position, x, y; #if defined(__OpenBSD__) /* What? */ int w, z; #else size_t w, z; #endif /* __OpenBSD__ */ char *smalbuf=NULL, *name=NULL, *cp; struct itimerval itv; bzero(&itv, sizeof(itv)); itv.it_interval.tv_sec = itv.it_value.tv_sec = 1; setitimer(ITIMER_REAL, &itv, NULL); signal(SIGALRM, checkFunc); while (!(maindisplay = XOpenDisplay(g.display))) sleep(2); bzero(&itv, sizeof(itv)); setitimer(ITIMER_REAL, &itv, NULL); mainscreen = DefaultScreen(maindisplay); backpix = BlackPixel(maindisplay, mainscreen); forepix = WhitePixel(maindisplay, mainscreen); colordepth = DefaultDepth(maindisplay, mainscreen); rootwindow = RootWindow(maindisplay, mainscreen); x = DisplayHeight(maindisplay, mainscreen); g.isize = ISIZE; for (;;) { g.msize = g.isize * g.xmag; if (g.panel) g.msize *= 2; if (g.msize > x) g.xmag--; else break; } g.psize = g.msize; if (g.panel) g.psize /= 2; if (g.pixmap) scaleGraphic(g.pixmap, TRUE); bzero(&sizehints, sizeof(sizehints)); sizehints.flags = USSize; CALLOC(smalbuf, SMALBUF, sizeof(char), "initWindow"); snprintf(smalbuf, SMALBUF, "%dx%d", g.isize, g.isize); XWMGeometry(maindisplay, mainscreen, smalbuf, NULL, 0, &sizehints, &sizehints.x, &sizehints.y, &sizehints.width, &sizehints.height, &sizehints.win_gravity); sizehints.min_width = sizehints.max_width = sizehints.width; sizehints.min_height = sizehints.max_height = sizehints.height; sizehints.flags |= PMinSize | PMaxSize | PWinGravity; iconmask = XCreatePixmap(maindisplay, rootwindow, sizehints.width, sizehints.height, colordepth); icondraw = XCreatePixmap(maindisplay, rootwindow, sizehints.width, sizehints.height, colordepth); iconwindow = XCreateSimpleWindow(maindisplay, rootwindow, sizehints.x, sizehints.y, sizehints.width, sizehints.height, 0, forepix, backpix); XSetWMNormalHints(maindisplay, iconwindow, &sizehints); wmhints.icon_window = iconwindow; if (g.withdrawn) { wmhints.window_group = iconwindow; wmhints.flags |= WindowGroupHint; } if (g.iconic || g.withdrawn) { wmhints.icon_x = sizehints.x; wmhints.icon_y = sizehints.y; wmhints.flags |= IconPositionHint; } bzero(&sizehints, sizeof(sizehints)); sizehints.flags = USSize; position = XParseGeometry(g.position, &x, &y, &w, &z); if (position & XValue && position & YValue) sizehints.flags |= USPosition; w = z = g.msize; if (position & XNegative && position & YNegative) snprintf(smalbuf, SMALBUF, "%dx%d-%d-%d", w, z, -x, -y); else if (position & XNegative) snprintf(smalbuf, SMALBUF, "%dx%d-%d+%d", w, z, -x, y); else if (position & YNegative) snprintf(smalbuf, SMALBUF, "%dx%d+%d-%d", w, z, x, -y); else snprintf(smalbuf, SMALBUF, "%dx%d+%d+%d", w, z, x, y); XWMGeometry(maindisplay, mainscreen, smalbuf, NULL, 0, &sizehints, &sizehints.x, &sizehints.y, &sizehints.width, &sizehints.height, &sizehints.win_gravity); FREE(smalbuf); sizehints.min_width = sizehints.max_width = sizehints.width; sizehints.min_height = sizehints.max_height = sizehints.height; sizehints.flags |= PMinSize | PMaxSize | PWinGravity; mainmask = XCreatePixmap(maindisplay, rootwindow, sizehints.width, sizehints.height, colordepth); maindraw = XCreatePixmap(maindisplay, rootwindow, sizehints.width, sizehints.height, colordepth); mainwindow = XCreateSimpleWindow(maindisplay, rootwindow, sizehints.x, sizehints.y, sizehints.width, sizehints.height, 0, forepix, backpix); XSetWMNormalHints(maindisplay, mainwindow, &sizehints); if (g.pixmap == 1) { XSetWindowBackgroundPixmap(maindisplay, iconwindow, ParentRelative); XSetWindowBackgroundPixmap(maindisplay, mainwindow, ParentRelative); } else { XSetWindowBackgroundPixmap(maindisplay, iconwindow, iconpix->pixmap); XSetWindowBackgroundPixmap(maindisplay, mainwindow, mainpix->pixmap); } if (g.appname) { XStringListToTextProperty(&g.appname, 1, &title); } else { /* Set the name only if not specified and only for X. */ cp = (strrchr(argv[0], SLASH)) ? strrchr(argv[0], SLASH) + 1 : argv[0]; STRDUP(name, cp); name[0] = toupper((int)name[0]); XStringListToTextProperty(&name, 1, &title); FREE(name); } XSetWMName(maindisplay, iconwindow, &title); XSetWMName(maindisplay, mainwindow, &title); classhint.res_name = (char *)title.value; classhint.res_class = (char *)title.value; XSetClassHint(maindisplay, mainwindow, &classhint); XStoreName(maindisplay, mainwindow, (char *)title.value); XSetIconName(maindisplay, mainwindow, (char *)title.value); XSelectInput(maindisplay, iconwindow, ExposureMask); XSelectInput(maindisplay, mainwindow, ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask); icongcv.background = backpix; icongcv.foreground = forepix; icongcv.graphics_exposures = False; icongc = XCreateGC(maindisplay, iconwindow, GCForeground | GCBackground, &icongcv); maingcv.background = backpix; maingcv.foreground = forepix; maingcv.graphics_exposures = False; maingc = XCreateGC(maindisplay, mainwindow, GCForeground | GCBackground, &maingcv); XSetCommand(maindisplay, mainwindow, argv, argc); wmdeletewindow = XInternAtom(maindisplay, "WM_DELETE_WINDOW", False); wmprotocols = XInternAtom(maindisplay, "WM_PROTOCOLS", False); XSetWMProtocols(maindisplay, iconwindow, &wmdeletewindow, 1); XSetWMProtocols(maindisplay, mainwindow, &wmdeletewindow, 1); wmhints.flags = StateHint | IconWindowHint; wmhints.initial_state = g.withdrawn ? WithdrawnState : g.iconic ? IconicState : NormalState; XSetWMHints(maindisplay, mainwindow, &wmhints); XMapWindow(maindisplay, mainwindow); }