2011-03-25 18:45:13 +00:00
|
|
|
/* $Id: wmpager.c,v 1.4 2002/08/16 17:22:26 essmann Exp $
|
|
|
|
*
|
|
|
|
* Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/xpm.h>
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
2012-08-22 16:40:31 +00:00
|
|
|
#include <sys/select.h>
|
2011-03-25 18:45:13 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "buttons.xpm"
|
|
|
|
#include "screen.xpm"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Constants
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define AUTHOR "Bruno Essmann <essmann@users.sourceforge.net>"
|
|
|
|
#define APPLICATION "wmpager"
|
|
|
|
#define VERSION "1.2"
|
|
|
|
|
2012-08-22 16:40:29 +00:00
|
|
|
#define XA_NET_NUMBER_OF_DESKTOPS "_NET_NUMBER_OF_DESKTOPS"
|
|
|
|
#define XA_NET_CURRENT_DESKTOP "_NET_CURRENT_DESKTOP"
|
|
|
|
#define XA_NET_DESKTOP_NAMES "_NET_DESKTOP_NAMES"
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
#define WMPAGER_ENV "WMPAGER"
|
2012-08-23 11:42:11 +00:00
|
|
|
#ifndef WMPAGER_DEFAULT_INSTALL_DIR
|
2011-03-25 18:45:13 +00:00
|
|
|
#define WMPAGER_DEFAULT_INSTALL_DIR "/usr/local/share/wmpager/"
|
2012-08-23 11:42:11 +00:00
|
|
|
#endif
|
2011-03-25 18:45:13 +00:00
|
|
|
#define WMPAGER_USER_DIR ".wmpager/"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prototypes
|
|
|
|
*/
|
|
|
|
|
|
|
|
void usage (int bVerbose);
|
|
|
|
void info ();
|
|
|
|
void setVerbose (int bVerbose);
|
|
|
|
int isVerbose ();
|
|
|
|
|
|
|
|
void initApplicationName (char* szApplicationName);
|
|
|
|
char* getApplicationName ();
|
|
|
|
|
|
|
|
void initDisplay (char* szDisplay);
|
|
|
|
void destroyDisplay ();
|
|
|
|
Display* getDisplay ();
|
|
|
|
|
|
|
|
Pixel getWhitePixel ();
|
|
|
|
Pixel getBlackPixel ();
|
|
|
|
int getDefaultScreen ();
|
|
|
|
int getDefaultDepth ();
|
|
|
|
void initWindow (int nArgc, char** szArgv);
|
|
|
|
void destroyWindow ();
|
|
|
|
GC getWindowGraphics ();
|
|
|
|
GC getMainGraphics ();
|
|
|
|
void initWindowMask (char* szInstallDir, char* szButtonTheme);
|
|
|
|
void redrawWindow ();
|
|
|
|
void getWindowOrigin (Window w, int* nX, int* nY);
|
|
|
|
|
2012-08-22 16:40:28 +00:00
|
|
|
void loop ();
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
void initButtons (int nButtons, int nColumns, int nRows);
|
|
|
|
int getButtonCount ();
|
|
|
|
int getButtonRowCount ();
|
|
|
|
int getButtonColumnCount ();
|
|
|
|
int getButtonWidth ();
|
|
|
|
int getButtonHeight ();
|
|
|
|
int getButtonAt (int nLocationX, int nLocationY);
|
|
|
|
void getButtonLocation (int nButton, int* nLocationX, int* nLocationY);
|
|
|
|
|
|
|
|
void initTime ();
|
|
|
|
long currentTimeMillis ();
|
|
|
|
|
|
|
|
void initScreens ();
|
|
|
|
int getScreenCount ();
|
|
|
|
char* getScreenName (int nScreen);
|
|
|
|
int getCurrentScreen ();
|
|
|
|
void setCurrentScreen (int nCurrentScreen);
|
|
|
|
void gotoScreen (int nWorkspace);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Main
|
|
|
|
*/
|
|
|
|
|
|
|
|
int main (int nArgc, char** szArgv) {
|
|
|
|
char* szDisplay= NULL;
|
|
|
|
char* szTheme= NULL;
|
|
|
|
char* szInstallDir= NULL;
|
|
|
|
int nWorkspaces= -1;
|
|
|
|
int bVerbose= 0;
|
|
|
|
int nSizeX= -1, nSizeY= -1;
|
|
|
|
int i;
|
|
|
|
initApplicationName(szArgv[0]);
|
|
|
|
/* we no longer use the WMPAGER environment variable
|
|
|
|
* szInstallDir= (char*) getenv(WMPAGER_ENV);
|
|
|
|
* instead we simply use a default installation directory
|
|
|
|
*/
|
|
|
|
szInstallDir= WMPAGER_DEFAULT_INSTALL_DIR;
|
|
|
|
i= 1;
|
|
|
|
while (i < nArgc) {
|
|
|
|
if (strcmp("-h", szArgv[i]) == 0 || strcmp("--help", szArgv[i]) == 0) {
|
|
|
|
usage(1);
|
|
|
|
} else if (strcmp("-v", szArgv[i]) == 0 || strcmp("--verbose", szArgv[i]) == 0) {
|
|
|
|
bVerbose= 1;
|
|
|
|
} else if (strcmp("-w", szArgv[i]) == 0 || strcmp("--workspaces", szArgv[i]) == 0) {
|
|
|
|
i+= 1;
|
|
|
|
if (i < nArgc) {
|
|
|
|
sscanf(szArgv[i], "%d", &nWorkspaces);
|
|
|
|
if (nWorkspaces <= 0 || nWorkspaces > 9) {
|
|
|
|
fprintf(stderr, "%s: illegal number of workspaces '%s' for option '%s' (has to be 1-9)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: workspace count expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else if (strcmp("-s", szArgv[i]) == 0 || strcmp("--size", szArgv[i]) == 0) {
|
|
|
|
i+= 1;
|
|
|
|
if (i < nArgc) {
|
|
|
|
sscanf(szArgv[i], "%dx%d", &nSizeX, &nSizeY);
|
|
|
|
if (nSizeX <= 0 || nSizeX > 3 || nSizeY <= 0 || nSizeY > 3) {
|
|
|
|
fprintf(stderr, "%s: illegal size '%s' for option '%s' (has to be 1x1 .. 3x3)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: size argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else if (strcmp("-i", szArgv[i]) == 0 || strcmp("--installdir", szArgv[i]) == 0) {
|
|
|
|
i+= 1;
|
|
|
|
if (i < nArgc) {
|
|
|
|
struct stat buf;
|
|
|
|
szInstallDir= szArgv[i];
|
|
|
|
if (stat(szInstallDir, &buf) != 0) {
|
|
|
|
fprintf(stderr, "%s: cannot access installation directory '%s'\n\n", getApplicationName(), szArgv[i]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else if (strcmp("-d", szArgv[i]) == 0 || strcmp("--display", szArgv[i]) == 0) {
|
|
|
|
i+= 1;
|
|
|
|
if (i < nArgc) {
|
|
|
|
szDisplay= szArgv[i];
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else if (strcmp("-t", szArgv[i]) == 0 || strcmp("--theme", szArgv[i]) == 0) {
|
|
|
|
i+= 1;
|
|
|
|
if (i < nArgc) {
|
2012-08-22 16:40:30 +00:00
|
|
|
szTheme= strdup(szArgv[i]);
|
2011-03-25 18:45:13 +00:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: theme argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: unknown option '%s'\n\n", getApplicationName(), szArgv[i]);
|
|
|
|
usage(0);
|
|
|
|
}
|
|
|
|
i+= 1;
|
|
|
|
}
|
|
|
|
setVerbose(bVerbose);
|
|
|
|
if (isVerbose()) {
|
|
|
|
char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
|
|
|
|
if (szRealDisplay == NULL) {
|
|
|
|
szRealDisplay= "localhost:0.0";
|
|
|
|
}
|
|
|
|
info();
|
|
|
|
fprintf(
|
|
|
|
stdout,
|
|
|
|
"[ ] startup options:\n" \
|
|
|
|
"[ ] - verbose= true\n" \
|
|
|
|
"[ ] - display= '%s'\n" \
|
|
|
|
"[ ] - installdir= '%s'\n" \
|
|
|
|
"[ ] - theme= '%s'\n" \
|
|
|
|
"[ ] - workspaces= '%d'\n" \
|
2012-08-22 16:40:28 +00:00
|
|
|
"[ ] - size= '%dx%d'\n",
|
2011-03-25 18:45:13 +00:00
|
|
|
szRealDisplay,
|
|
|
|
szInstallDir == NULL ? "<undefined>" : szInstallDir,
|
|
|
|
szTheme == NULL ? "<built-in>" : szTheme,
|
|
|
|
nWorkspaces,
|
2012-08-22 16:40:28 +00:00
|
|
|
nSizeX, nSizeY
|
2011-03-25 18:45:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
initTime();
|
|
|
|
initDisplay(szDisplay);
|
|
|
|
initWindow(nArgc, szArgv);
|
|
|
|
initScreens();
|
|
|
|
initButtons(nWorkspaces, nSizeX, nSizeY);
|
|
|
|
initWindowMask(szInstallDir, szTheme);
|
2012-08-22 16:40:28 +00:00
|
|
|
loop();
|
2011-03-25 18:45:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verbose
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int _bVerbose;
|
|
|
|
|
|
|
|
void setVerbose (int bVerbose) {
|
|
|
|
_bVerbose= bVerbose;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isVerbose () {
|
|
|
|
return _bVerbose;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Usage
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define USAGE \
|
|
|
|
"usage: %s [options]\n\n" \
|
|
|
|
"where options include:\n" \
|
|
|
|
" -h --help display usage and version information\n" \
|
|
|
|
" -v --verbose verbose message output\n" \
|
|
|
|
" -d --display <name> the display to use (defaults to the\n" \
|
|
|
|
" 'DISPLAY' environment variable)\n" \
|
|
|
|
" -s --size <w>x<h> number of buttons (default depends on the\n" \
|
|
|
|
" number of workspaces you have, i.e. 2x2 for 4\n" \
|
|
|
|
" workspaces, 2x3 for 6, maximum is 3x3)\n" \
|
|
|
|
" -w --workspaces <count> number of workspace buttons to display\n" \
|
|
|
|
" (default is the number of workspaces you have,\n" \
|
|
|
|
" maximum is 9)\n" \
|
|
|
|
" -t --theme <theme.xpm> the button theme to use, extension\n" \
|
|
|
|
" '.xpm' is optional, for more information about\n" \
|
|
|
|
" themes see docu (default is the built-in theme)\n" \
|
|
|
|
" -i --installdir <dir> specifies the installation directory location,\n" \
|
|
|
|
" this location is automatically searched for themes\n" \
|
|
|
|
" (defaults to the '/usr/local/share/wmpager/'\n" \
|
2012-08-22 16:40:28 +00:00
|
|
|
" and the user specific '~/.wmpager' directory)\n"
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
void usage (int bVerbose) {
|
|
|
|
if (bVerbose) {
|
|
|
|
info();
|
|
|
|
fprintf(stdout, USAGE, getApplicationName());
|
|
|
|
exit(0);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, USAGE, getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void info () {
|
2012-08-22 16:40:30 +00:00
|
|
|
fprintf(stdout, "%s %s\n\n", APPLICATION, VERSION);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Application
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char* _szApplicationName;
|
|
|
|
|
|
|
|
char* getApplicationName () {
|
|
|
|
return _szApplicationName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void initApplicationName (char* szApplicationName) {
|
|
|
|
if (szApplicationName == NULL) {
|
|
|
|
_szApplicationName= APPLICATION;
|
|
|
|
} else {
|
|
|
|
_szApplicationName= strdup(szApplicationName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display
|
|
|
|
*/
|
|
|
|
|
|
|
|
static Display* _display;
|
2012-08-22 16:40:31 +00:00
|
|
|
static int _xfd;
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
Display* getDisplay () {
|
|
|
|
return _display;
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroyDisplay () {
|
|
|
|
XCloseDisplay(getDisplay());
|
|
|
|
}
|
|
|
|
|
|
|
|
void initDisplay (char* szDisplay) {
|
|
|
|
if (szDisplay == NULL && ((char*) getenv("DISPLAY")) == NULL) {
|
|
|
|
szDisplay= ":0.0";
|
|
|
|
}
|
|
|
|
if (isVerbose()) {
|
|
|
|
char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
|
|
|
|
if (szRealDisplay == NULL) {
|
|
|
|
szRealDisplay= "localhost:0.0";
|
|
|
|
}
|
|
|
|
fprintf(stdout, "[%8ld] initializing display '%s'\n", currentTimeMillis(), szRealDisplay);
|
|
|
|
}
|
|
|
|
_display= XOpenDisplay(szDisplay);
|
|
|
|
if (_display == NULL) {
|
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"%s: couldn't open display '%s'.\n",
|
|
|
|
getApplicationName(),
|
|
|
|
(szDisplay == NULL) ? ((char*) getenv("DISPLAY")) : szDisplay
|
|
|
|
);
|
|
|
|
exit(-1);
|
|
|
|
}
|
2012-08-22 16:40:31 +00:00
|
|
|
_xfd= XConnectionNumber(_display);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Window
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int _nDefaultScreen, _nDefaultDepth;
|
|
|
|
static Window _wRoot, _wMain, _wIcon;
|
|
|
|
static GC _gcMain, _gcWindow;
|
|
|
|
static XpmAttributes _attrButtonTheme;
|
|
|
|
static Pixmap _pButtonTheme, _pButtonThemeMask;
|
|
|
|
static XpmAttributes _attrWindow;
|
|
|
|
static Pixmap _pWindow, _pWindowMask;
|
|
|
|
static Pixel _pWhite, _pBlack;
|
|
|
|
|
|
|
|
Pixel getWhitePixel () {
|
|
|
|
return _pWhite;
|
|
|
|
}
|
|
|
|
|
|
|
|
Pixel getBlackPixel () {
|
|
|
|
return _pBlack;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getDefaultScreen () {
|
|
|
|
return _nDefaultScreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getDefaultDepth () {
|
|
|
|
return _nDefaultDepth;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window getRootWindow () {
|
|
|
|
return _wRoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window getMainWindow () {
|
|
|
|
return _wMain;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window getIconWindow () {
|
|
|
|
return _wIcon;
|
|
|
|
}
|
|
|
|
|
|
|
|
GC getMainGraphics () {
|
|
|
|
return _gcMain;
|
|
|
|
}
|
|
|
|
|
|
|
|
GC getWindowGraphics () {
|
|
|
|
return _gcWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
void initWindow (int nArgc, char** szArgv) {
|
|
|
|
char* szApplicationName= getApplicationName();
|
|
|
|
Display* display= getDisplay();
|
|
|
|
XSizeHints *xsizehints;
|
|
|
|
XWMHints* xwmhints;
|
|
|
|
XClassHint* xclasshint;
|
2012-08-22 16:40:30 +00:00
|
|
|
XTextProperty xtApplication;
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing application window\n", currentTimeMillis());
|
|
|
|
}
|
|
|
|
|
|
|
|
_nDefaultScreen= DefaultScreen(display);
|
|
|
|
_nDefaultDepth= DefaultDepth(display, _nDefaultScreen);
|
|
|
|
_wRoot= RootWindow(display, _nDefaultScreen);
|
|
|
|
|
|
|
|
XSelectInput(display, _wRoot, PropertyChangeMask);
|
|
|
|
|
|
|
|
_pWhite= WhitePixel(display, _nDefaultScreen);
|
|
|
|
_pBlack= BlackPixel(display, _nDefaultScreen);
|
|
|
|
|
|
|
|
xsizehints= XAllocSizeHints();
|
|
|
|
xsizehints->flags= USSize | USPosition;
|
|
|
|
xsizehints->width= xsizehints->height= 64;
|
|
|
|
|
|
|
|
_wMain= XCreateSimpleWindow(display, _wRoot, 0, 0, 64, 64, 5, _pWhite, _pBlack);
|
|
|
|
if (_wMain == 0) {
|
|
|
|
fprintf(stderr, "Cannot create main window.\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
_wIcon= XCreateSimpleWindow(display, _wMain, 0, 0, 64, 64, 5, _pWhite, _pBlack);
|
|
|
|
if (_wIcon == 0) {
|
|
|
|
fprintf(stderr, "Cannot create icon window.\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
xwmhints= XAllocWMHints();
|
|
|
|
xwmhints->flags= WindowGroupHint | IconWindowHint | StateHint;
|
|
|
|
xwmhints->icon_window= _wIcon;
|
|
|
|
xwmhints->window_group= _wMain;
|
|
|
|
xwmhints->initial_state= WithdrawnState;
|
|
|
|
XSetWMHints(display, _wMain, xwmhints);
|
|
|
|
|
|
|
|
xclasshint= XAllocClassHint();
|
|
|
|
xclasshint->res_name= APPLICATION;
|
|
|
|
xclasshint->res_class= APPLICATION;
|
|
|
|
XSetClassHint(display, _wMain, xclasshint);
|
|
|
|
|
|
|
|
XSetWMNormalHints(display, _wMain, xsizehints);
|
|
|
|
|
2012-08-22 16:40:30 +00:00
|
|
|
XFree(xclasshint);
|
|
|
|
XFree(xwmhints);
|
|
|
|
XFree(xsizehints);
|
|
|
|
|
|
|
|
if (XStringListToTextProperty(&szApplicationName, 1, &xtApplication) == 0) {
|
2011-03-25 18:45:13 +00:00
|
|
|
fprintf(stderr, "Cannot set window title.\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
XSetWMName(display, _wMain, &xtApplication);
|
|
|
|
XFree(xtApplication.value);
|
2011-03-25 18:45:13 +00:00
|
|
|
|
2012-08-22 16:40:30 +00:00
|
|
|
_gcMain= XCreateGC(display, _wMain, 0L, NULL);
|
2011-03-25 18:45:13 +00:00
|
|
|
if (_gcMain == NULL) {
|
|
|
|
fprintf(stderr, "Cannot create graphics context.\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
XSelectInput(display, _wMain, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
|
|
|
|
XSelectInput(display, _wIcon, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
|
|
|
|
|
|
|
|
XSetCommand(display, _wMain, szArgv, nArgc);
|
|
|
|
|
|
|
|
XMapWindow(display, _wMain);
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroyWindow () {
|
|
|
|
XFreeGC(getDisplay(), getWindowGraphics());
|
|
|
|
XFreeGC(getDisplay(), getMainGraphics());
|
|
|
|
XDestroyWindow(getDisplay(), getMainWindow());
|
|
|
|
XDestroyWindow(getDisplay(), getIconWindow());
|
|
|
|
}
|
|
|
|
|
|
|
|
void initWindowMask (char* szInstallDir, char* szButtonTheme) {
|
|
|
|
Display* display= getDisplay();
|
|
|
|
GC gc;
|
|
|
|
Window wRoot= getRootWindow();
|
|
|
|
Window wMain= getMainWindow();
|
|
|
|
Window wIcon= getIconWindow();
|
|
|
|
Pixmap pOpaque, pTransparent, pMask;
|
|
|
|
char* mask= (char*) malloc(512);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing window mask\n", currentTimeMillis());
|
|
|
|
}
|
|
|
|
for (i= 0; i < 512; i++) {
|
|
|
|
mask[i]= 0x00;
|
|
|
|
}
|
|
|
|
pTransparent= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
|
|
|
|
if (pTransparent == 0) {
|
|
|
|
fprintf(stderr, "%s: couldn't create window mask (transparent).\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
pMask= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
|
|
|
|
if (pMask == 0) {
|
|
|
|
fprintf(stderr, "%s: couldn't create window mask (mask buffer).\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i= 0; i < 512; i++) {
|
|
|
|
mask[i]= 0xff;
|
|
|
|
}
|
|
|
|
pOpaque= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
|
|
|
|
if (pOpaque == 0) {
|
|
|
|
fprintf(stderr, "%s: couldn't create window mask (opaque).\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2012-08-22 16:40:30 +00:00
|
|
|
gc= XCreateGC(display, pMask, 0L, NULL);
|
2011-03-25 18:45:13 +00:00
|
|
|
if (gc == NULL) {
|
|
|
|
fprintf(stderr, "%s: couldn't create window mask (mask graphics).\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
for (i= 0; i < getButtonCount(); i++) {
|
|
|
|
int nButtonX, nButtonY;
|
|
|
|
getButtonLocation(i, &nButtonX, &nButtonY);
|
|
|
|
XCopyArea(display, pOpaque, pMask, gc, nButtonX, nButtonY, getButtonWidth(), getButtonHeight(), nButtonX, nButtonY);
|
|
|
|
}
|
|
|
|
|
2012-08-22 16:40:30 +00:00
|
|
|
free(mask);
|
2011-03-25 18:45:13 +00:00
|
|
|
XFreePixmap(display, pOpaque);
|
|
|
|
XFreePixmap(display, pTransparent);
|
|
|
|
XFreeGC(display, gc);
|
|
|
|
|
|
|
|
XShapeCombineMask(display, wMain, ShapeBounding, 0, 0, pMask, ShapeSet);
|
|
|
|
XShapeCombineMask(display, wIcon, ShapeBounding, 0, 0, pMask, ShapeSet);
|
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(),
|
|
|
|
szButtonTheme == NULL ? "<built-in>" : szButtonTheme);
|
|
|
|
}
|
|
|
|
|
|
|
|
_attrButtonTheme.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
|
|
|
|
if (szButtonTheme == NULL) {
|
|
|
|
if (
|
|
|
|
XpmCreatePixmapFromData(
|
|
|
|
display, wRoot, buttons_xpm, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
|
|
|
|
) != XpmSuccess
|
|
|
|
) {
|
|
|
|
fprintf(stderr, "%s: couldn't create button theme.\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int bCheckAgain= 0;
|
|
|
|
struct stat buf;
|
|
|
|
/* check for absolute button theme pathname */
|
|
|
|
if (stat(szButtonTheme, &buf) == -1) {
|
2012-08-22 16:40:30 +00:00
|
|
|
char* szNewTheme= (char*) malloc(strlen(szButtonTheme) + 5);
|
2011-03-25 18:45:13 +00:00
|
|
|
strcpy(szNewTheme, szButtonTheme);
|
|
|
|
strcat(szNewTheme, ".xpm");
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] theme file '%s' not found, trying '%s'\n", currentTimeMillis(), szButtonTheme, szNewTheme);
|
|
|
|
}
|
|
|
|
/* check for absolute button theme pathname (with .xpm added) */
|
|
|
|
if (stat(szNewTheme, &buf) == 0) {
|
2012-08-22 16:40:30 +00:00
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
szButtonTheme= szNewTheme;
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bCheckAgain= 1;
|
|
|
|
free(szNewTheme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bCheckAgain && szInstallDir != NULL) {
|
2012-08-22 16:40:30 +00:00
|
|
|
char* szNewTheme= (char*) malloc(strlen(szInstallDir) + strlen(szButtonTheme) + 6);
|
2011-03-25 18:45:13 +00:00
|
|
|
strcpy(szNewTheme, szInstallDir);
|
|
|
|
if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
|
|
|
|
strcat(szNewTheme, "/");
|
|
|
|
}
|
|
|
|
strcat(szNewTheme, szButtonTheme);
|
|
|
|
if (stat(szNewTheme, &buf) == 0) {
|
|
|
|
bCheckAgain= 0;
|
2012-08-22 16:40:30 +00:00
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
szButtonTheme= szNewTheme;
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
strcat(szNewTheme, ".xpm");
|
|
|
|
if (stat(szNewTheme, &buf) == 0) {
|
|
|
|
bCheckAgain= 0;
|
2012-08-22 16:40:30 +00:00
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
szButtonTheme= szNewTheme;
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
} else {
|
|
|
|
free(szNewTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bCheckAgain) {
|
|
|
|
/* as a goody check the ~/.wmpager directory if it exists */
|
|
|
|
char* szHome= (char*) getenv("HOME");
|
|
|
|
if (szHome) {
|
|
|
|
/* one really shouldn't copy&paste but hey this is a q&d tool */
|
2012-08-22 16:40:30 +00:00
|
|
|
char* szNewTheme= (char*) malloc(strlen(szHome) + strlen(szButtonTheme) + strlen(WMPAGER_USER_DIR) + 6);
|
2011-03-25 18:45:13 +00:00
|
|
|
strcpy(szNewTheme, szHome);
|
|
|
|
if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
|
|
|
|
strcat(szNewTheme, "/");
|
|
|
|
}
|
|
|
|
strcat(szNewTheme, WMPAGER_USER_DIR);
|
|
|
|
strcat(szNewTheme, szButtonTheme);
|
|
|
|
if (stat(szNewTheme, &buf) == 0) {
|
|
|
|
bCheckAgain= 0;
|
2012-08-22 16:40:30 +00:00
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
szButtonTheme= szNewTheme;
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
strcat(szNewTheme, ".xpm");
|
|
|
|
if (stat(szNewTheme, &buf) == 0) {
|
|
|
|
bCheckAgain= 0;
|
2012-08-22 16:40:30 +00:00
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
szButtonTheme= szNewTheme;
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
} else {
|
|
|
|
free(szNewTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
XpmReadFileToPixmap(
|
|
|
|
display, wRoot, szButtonTheme, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
|
|
|
|
) != XpmSuccess
|
|
|
|
) {
|
|
|
|
fprintf(stderr, "%s: couldn't read button theme '%s'.\n", getApplicationName(), szButtonTheme);
|
|
|
|
exit(-1);
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
|
|
|
|
free(szButtonTheme);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing screen buffer\n", currentTimeMillis());
|
|
|
|
}
|
|
|
|
|
|
|
|
_attrWindow.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
|
|
|
|
if (
|
|
|
|
XpmCreatePixmapFromData(
|
|
|
|
display, wRoot, screen_xpm, &_pWindow, &_pWindowMask, &_attrWindow
|
|
|
|
) != XpmSuccess
|
|
|
|
) {
|
|
|
|
fprintf(stderr, "%s: couldn't create screen buffer.\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2012-08-22 16:40:30 +00:00
|
|
|
_gcWindow= XCreateGC(_display, _pWindow, 0L, NULL);
|
|
|
|
if (_gcWindow == NULL) {
|
2011-03-25 18:45:13 +00:00
|
|
|
fprintf(stderr, "%s: couldn't create screen buffer graphics.\n", getApplicationName());
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void redrawWindow () {
|
|
|
|
XEvent event;
|
|
|
|
int i;
|
|
|
|
int w= getButtonWidth();
|
|
|
|
int h= getButtonHeight();
|
|
|
|
for (i= 0; i < getButtonCount(); i++) {
|
|
|
|
int x, y, xoff, yoff;
|
|
|
|
xoff= 51;
|
|
|
|
yoff= 10;
|
|
|
|
if (i == getCurrentScreen()) {
|
|
|
|
xoff= 0;
|
|
|
|
yoff= 0;
|
|
|
|
}
|
|
|
|
getButtonLocation(i, &x, &y);
|
|
|
|
XSetClipMask(_display, _gcWindow, _pWindowMask);
|
|
|
|
XSetClipOrigin(_display, _gcWindow, 0, 0);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + x - 7, y - 7, w, h, x, y);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, w, 1, x, y);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, 1, h, x, y);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + 50, 0, 1, h, x + w - 1, y);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 50, w, 1, x, y + h - 1);
|
|
|
|
XSetClipMask(_display, _gcWindow, _pButtonThemeMask);
|
|
|
|
XSetClipOrigin(_display, _gcWindow, (x + (w - 10) / 2) - i * 10, -51 - yoff + y + (h - 10) / 2);
|
|
|
|
XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, i * 10, 51 + yoff, 10, 10, x + (w - 10) / 2, y + (h - 10) / 2);
|
|
|
|
}
|
|
|
|
while (XCheckTypedWindowEvent(_display, _wMain, Expose, &event));
|
|
|
|
XCopyArea(_display, _pWindow, _wMain, _gcMain, 0, 0, 64, 64, 0, 0);
|
|
|
|
while (XCheckTypedWindowEvent(_display, _wIcon, Expose, &event));
|
|
|
|
XCopyArea(_display, _pWindow, _wIcon, _gcMain, 0, 0, 64, 64, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void getWindowOrigin (Window w, int* nX, int* nY) {
|
|
|
|
Window wWindow, wParent, wRoot;
|
|
|
|
Window* wChildren;
|
|
|
|
unsigned int nChildren;
|
|
|
|
unsigned int ww, wh, wb, wd;
|
|
|
|
int wx, wy;
|
|
|
|
|
|
|
|
wParent= w;
|
|
|
|
do {
|
|
|
|
wWindow= wParent;
|
|
|
|
if (!XQueryTree(getDisplay(), wParent, &wRoot, &wParent, &wChildren, &nChildren)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (wChildren) {
|
|
|
|
XFree(wChildren);
|
|
|
|
}
|
|
|
|
} while (wParent != wRoot);
|
|
|
|
|
|
|
|
if (XGetGeometry(getDisplay(), wWindow, &wRoot, &wx, &wy, &ww, &wh, &wb, &wd)) {
|
|
|
|
if (nX) {
|
|
|
|
*nX= wx;
|
|
|
|
}
|
|
|
|
if (nY) {
|
|
|
|
*nY= wy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Event Loop
|
|
|
|
*/
|
|
|
|
|
2012-08-22 16:40:28 +00:00
|
|
|
void loop () {
|
2011-03-25 18:45:13 +00:00
|
|
|
Display* display= getDisplay();
|
|
|
|
XEvent event;
|
2012-08-22 16:40:30 +00:00
|
|
|
char* atom_name;
|
2012-08-22 16:40:31 +00:00
|
|
|
struct timeval tv;
|
|
|
|
fd_set fds;
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] starting event loop\n", currentTimeMillis());
|
|
|
|
}
|
|
|
|
for (;;) {
|
2012-08-22 16:40:28 +00:00
|
|
|
while (XPending(display)) {
|
2011-03-25 18:45:13 +00:00
|
|
|
XNextEvent(display, &event);
|
|
|
|
switch (event.type) {
|
|
|
|
case Expose:
|
|
|
|
if (event.xexpose.count == 0) {
|
|
|
|
redrawWindow();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
|
|
redrawWindow();
|
|
|
|
break;
|
|
|
|
case ButtonPress:
|
|
|
|
{
|
|
|
|
int nButton= getButtonAt(event.xbutton.x, event.xbutton.y);
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] button %d pressed\n", currentTimeMillis(), nButton);
|
|
|
|
}
|
|
|
|
if (nButton != -1) {
|
|
|
|
setCurrentScreen(nButton);
|
|
|
|
gotoScreen(nButton);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PropertyNotify:
|
2012-08-22 16:40:30 +00:00
|
|
|
atom_name = XGetAtomName(getDisplay(), event.xproperty.atom);
|
|
|
|
if (atom_name == NULL)
|
|
|
|
break;
|
|
|
|
if (strcmp(XA_NET_CURRENT_DESKTOP, atom_name) == 0) {
|
2011-03-25 18:45:13 +00:00
|
|
|
setCurrentScreen(-1);
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] new current workspace (%d= %s)\n",
|
|
|
|
currentTimeMillis(), getCurrentScreen(), getScreenName(getCurrentScreen()));
|
|
|
|
}
|
|
|
|
redrawWindow();
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
XFree(atom_name);
|
2011-03-25 18:45:13 +00:00
|
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] quit application\n", currentTimeMillis());
|
|
|
|
}
|
|
|
|
destroyWindow();
|
|
|
|
destroyDisplay();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-22 16:40:31 +00:00
|
|
|
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = 500000UL;
|
|
|
|
FD_ZERO(&fds);
|
|
|
|
FD_SET(_xfd, &fds);
|
|
|
|
select(_xfd + 1, &fds, NULL, NULL, &tv);
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Button Helpers
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int _nButtons;
|
|
|
|
static int _nButtonRows, _nButtonColumns;
|
|
|
|
static int _nButtonWidth, _nButtonHeight;
|
|
|
|
|
|
|
|
int getButtonCount () {
|
|
|
|
return _nButtons;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getButtonRowCount () {
|
|
|
|
return _nButtonRows;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getButtonColumnCount () {
|
|
|
|
return _nButtonColumns;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getButtonWidth () {
|
|
|
|
return _nButtonWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getButtonHeight () {
|
|
|
|
return _nButtonHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getButtonAt (int nLocationX, int nLocationY) {
|
|
|
|
int i, nButtonX, nButtonY;
|
|
|
|
for (i= 0; i < _nButtons; i++) {
|
|
|
|
getButtonLocation(i, &nButtonX, &nButtonY);
|
|
|
|
if (
|
|
|
|
nLocationX >= nButtonX && nLocationX < nButtonX + _nButtonWidth &&
|
|
|
|
nLocationY >= nButtonY && nLocationY < nButtonY + _nButtonHeight
|
|
|
|
) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getButtonLocation (int nButton, int* nLocationX, int* nLocationY) {
|
|
|
|
if (nButton < 0 || nButton > _nButtons) {
|
|
|
|
*nLocationX= *nLocationY= 0;
|
|
|
|
} else {
|
|
|
|
*nLocationX= *nLocationY= 7;
|
|
|
|
while (nButton >= _nButtonColumns) {
|
|
|
|
*nLocationY+= _nButtonHeight + 3;
|
|
|
|
nButton-= _nButtonColumns;
|
|
|
|
}
|
|
|
|
while (nButton > 0) {
|
|
|
|
*nLocationX+= _nButtonWidth + 3;
|
|
|
|
nButton--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void initButtons (int nButtons, int nColumns, int nRows) {
|
|
|
|
if (nButtons != -1) {
|
|
|
|
_nButtons= nButtons;
|
|
|
|
} else {
|
|
|
|
_nButtons= getScreenCount();
|
|
|
|
if (_nButtons > 9) {
|
|
|
|
/* only handle nine screens at most */
|
|
|
|
_nButtons= 9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nColumns == -1 || nRows == -1) {
|
|
|
|
switch (_nButtons) {
|
|
|
|
case 1:
|
|
|
|
_nButtonRows= _nButtonColumns= 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
_nButtonColumns= 1;
|
|
|
|
_nButtonRows= 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
/* fallthrough */
|
|
|
|
case 4:
|
|
|
|
_nButtonColumns= _nButtonRows= 2;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
/* fallthrough */
|
|
|
|
case 6:
|
|
|
|
_nButtonColumns= 2;
|
|
|
|
_nButtonRows= 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_nButtonColumns= _nButtonRows= 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_nButtonColumns= nColumns;
|
|
|
|
_nButtonRows= nRows;
|
|
|
|
}
|
|
|
|
if (_nButtons > _nButtonColumns * _nButtonRows) {
|
|
|
|
_nButtons= _nButtonColumns * _nButtonRows;
|
|
|
|
}
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing buttons\n", currentTimeMillis());
|
|
|
|
fprintf(stdout, "[%8ld] - %d workspace buttons\n", currentTimeMillis(), _nButtons);
|
|
|
|
fprintf(stdout, "[%8ld] - button layout %dx%d\n", currentTimeMillis(), _nButtonColumns, _nButtonRows);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_nButtonColumns == 1) {
|
|
|
|
_nButtonWidth= 51;
|
|
|
|
} else if (_nButtonColumns == 2) {
|
|
|
|
_nButtonWidth= 24;
|
|
|
|
} else {
|
|
|
|
_nButtonWidth= 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_nButtonRows == 1) {
|
|
|
|
_nButtonHeight= 51;
|
|
|
|
} else if (_nButtonRows == 2) {
|
|
|
|
_nButtonHeight= 24;
|
|
|
|
} else {
|
|
|
|
_nButtonHeight= 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Time
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct timeval _tStart;
|
|
|
|
|
|
|
|
void initTime () {
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[ ] initializing time\n");
|
|
|
|
}
|
|
|
|
gettimeofday(&_tStart, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
long currentTimeMillis () {
|
|
|
|
struct timeval tNow;
|
|
|
|
struct timeval tElapsed;
|
|
|
|
|
|
|
|
gettimeofday(&tNow, NULL);
|
|
|
|
|
|
|
|
if (_tStart.tv_usec > tNow.tv_usec) {
|
|
|
|
tNow.tv_usec+= 1000000;
|
|
|
|
tNow.tv_sec--;
|
|
|
|
}
|
|
|
|
tElapsed.tv_sec= tNow.tv_sec - _tStart.tv_sec;
|
|
|
|
tElapsed.tv_usec= tNow.tv_usec - _tStart.tv_usec;
|
|
|
|
return (tElapsed.tv_sec * 1000) + (tElapsed.tv_usec / 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Screen Handling
|
|
|
|
*/
|
|
|
|
|
2012-08-22 16:40:29 +00:00
|
|
|
static Atom _xaNetNumberOfDesktops;
|
|
|
|
static Atom _xaNetCurrentDesktop;
|
|
|
|
static Atom _xaNetDesktopNames;
|
2011-03-25 18:45:13 +00:00
|
|
|
static int _nScreens;
|
|
|
|
static char** _szScreenNames;
|
2012-08-22 16:40:29 +00:00
|
|
|
static int _nDesktopNames;
|
2011-03-25 18:45:13 +00:00
|
|
|
static int _nLastScreen;
|
|
|
|
|
|
|
|
int getScreenCount () {
|
|
|
|
return _nScreens;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* getScreenName (int nScreen) {
|
2012-08-22 16:40:29 +00:00
|
|
|
if (nScreen < 0 || nScreen >= _nDesktopNames) {
|
|
|
|
return "<empty>";
|
2011-03-25 18:45:13 +00:00
|
|
|
}
|
|
|
|
return _szScreenNames[nScreen];
|
|
|
|
}
|
|
|
|
|
|
|
|
void gotoScreen (int nWorkspace) {
|
|
|
|
XEvent event;
|
|
|
|
event.type= ClientMessage;
|
|
|
|
event.xclient.type= ClientMessage;
|
|
|
|
event.xclient.window= getRootWindow();
|
2012-08-22 16:40:29 +00:00
|
|
|
event.xclient.message_type= _xaNetCurrentDesktop;
|
2011-03-25 18:45:13 +00:00
|
|
|
event.xclient.format= 32;
|
|
|
|
event.xclient.data.l[0]= nWorkspace;
|
|
|
|
event.xclient.data.l[1]= currentTimeMillis();
|
|
|
|
XSendEvent(getDisplay(), getRootWindow(), False, SubstructureNotifyMask, (XEvent*) &event);
|
|
|
|
}
|
|
|
|
|
|
|
|
int getCurrentScreen () {
|
|
|
|
return _nLastScreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentScreen (int nCurrentScreen) {
|
|
|
|
if (nCurrentScreen == -1) {
|
|
|
|
long nScreen= _nLastScreen;
|
|
|
|
Atom xaType;
|
|
|
|
int nFormat;
|
|
|
|
unsigned long nItems, nBytesAfter;
|
|
|
|
unsigned char* data;
|
|
|
|
|
|
|
|
XGetWindowProperty(
|
2012-08-22 16:40:29 +00:00
|
|
|
getDisplay(), getRootWindow(), _xaNetCurrentDesktop,
|
2011-03-25 18:45:13 +00:00
|
|
|
0, 8192, False, XA_CARDINAL, &xaType, &nFormat, &nItems, &nBytesAfter, &data
|
|
|
|
);
|
|
|
|
if ((nFormat == 32) && (nItems == 1) && (nBytesAfter == 0)) {
|
|
|
|
nScreen= *(long*) data;
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
XFree(data);
|
2011-03-25 18:45:13 +00:00
|
|
|
_nLastScreen= nScreen;
|
|
|
|
} else {
|
|
|
|
_nLastScreen= nCurrentScreen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void initScreens () {
|
|
|
|
XTextProperty tp;
|
2012-08-22 16:40:29 +00:00
|
|
|
Atom xaType;
|
|
|
|
int nFormat;
|
|
|
|
unsigned long nItems, nBytesAfter;
|
|
|
|
unsigned char* data;
|
2011-03-25 18:45:13 +00:00
|
|
|
|
|
|
|
if (isVerbose()) {
|
|
|
|
fprintf(stdout, "[%8ld] initializing window maker communication\n", currentTimeMillis());
|
|
|
|
}
|
2012-08-22 16:40:29 +00:00
|
|
|
_xaNetNumberOfDesktops= XInternAtom(getDisplay(), XA_NET_NUMBER_OF_DESKTOPS, False);
|
|
|
|
_xaNetCurrentDesktop= XInternAtom(getDisplay(), XA_NET_CURRENT_DESKTOP, False);
|
|
|
|
_xaNetDesktopNames= XInternAtom(getDisplay(), XA_NET_DESKTOP_NAMES, False);
|
|
|
|
|
|
|
|
XGetWindowProperty(
|
|
|
|
getDisplay(), getRootWindow(), _xaNetNumberOfDesktops,
|
|
|
|
0, 8192, False, XA_CARDINAL, &xaType, &nFormat, &nItems, &nBytesAfter, &data
|
|
|
|
);
|
|
|
|
if ((nFormat == 32) && (nItems == 1) && (nBytesAfter == 0)) {
|
|
|
|
_nScreens= *(long*) data;
|
|
|
|
}
|
2012-08-22 16:40:30 +00:00
|
|
|
XFree(data);
|
2012-08-22 16:40:29 +00:00
|
|
|
|
|
|
|
XGetTextProperty(getDisplay(), getRootWindow(), &tp, _xaNetDesktopNames);
|
|
|
|
Xutf8TextPropertyToTextList(getDisplay(), &tp, &_szScreenNames, &_nDesktopNames);
|
2012-08-22 16:40:30 +00:00
|
|
|
XFree(tp.value);
|
2012-08-22 16:40:29 +00:00
|
|
|
|
2011-03-25 18:45:13 +00:00
|
|
|
_nLastScreen= -1;
|
|
|
|
setCurrentScreen(-1);
|
|
|
|
if (_nLastScreen == -1) {
|
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"%s: couldn't determine current workspace.\n" \
|
2012-08-22 16:40:29 +00:00
|
|
|
"Make sure your WindowMaker has EWMH support enabled!\n",
|
2011-03-25 18:45:13 +00:00
|
|
|
getApplicationName()
|
|
|
|
);
|
|
|
|
setCurrentScreen(0);
|
|
|
|
}
|
|
|
|
if (isVerbose()) {
|
|
|
|
int i;
|
|
|
|
fprintf(stdout, "[%8ld] - %d worspaces found\n", currentTimeMillis(), getScreenCount());
|
|
|
|
for (i= 0; i < getScreenCount(); i++) {
|
|
|
|
fprintf(stdout, "[%8ld] - workspace %d: %s\n", currentTimeMillis(), i, getScreenName(i));
|
|
|
|
}
|
|
|
|
fprintf(stdout, "[%8ld] - current workspace is %d (%s)\n", currentTimeMillis(),
|
|
|
|
getCurrentScreen(), getScreenName(getCurrentScreen()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|