/* FvwmWinList Module for Fvwm.
*
* Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or
* Mike_Finger@atk.com)
*
* The author makes not guarantees or warantees, either express or
* implied. Feel free to use any contained here for any purpose, as long
* and this and any other applicible copyrights are kept intact.
*
* The functions in this source file that are based on part of the FvwmIdent
* module for Fvwm are noted by a small copyright atop that function, all
* others are copyrighted by Mike Finger. For those functions modified/used,
* here is the full, origonal copyright:
*
* Copyright 1994, Robert Nation and Nobutaka Suzuki.
* No guarantees or warantees or anything
* are provided or implied in any way whatsoever. Use this program at your
* own risk. Permission to use this program for any purpose is given,
* as long as the copyright is kept intact.
*
* Modifications Done to Add Pixmaps, focus highlighting and Current Desk Only
* By Don Mahurin, 1996, Some of this Code was taken from FvwmTaskBar
*/
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NO_CONSOLE
#define NO_CONSOLE
#endif
#define YES "Yes"
#define NO "No"
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/time.h>
#ifdef HAVE_SYS_BSDTYPES_H
#include <sys/bsdtypes.h> /* Saul */
#endif
#include <stdlib.h>
#include "libs/Module.h"
#include "libs/fvwmsignal.h"
#include "libs/fvwmlib.h"
#include "libs/FScreen.h"
#include "libs/FShape.h"
#include "FvwmWinList.h"
#include "ButtonArray.h"
#include "List.h"
#include "Mallocs.h"
#include "libs/Colorset.h"
#ifdef I18N_MB
#include <X11/Xlocale.h>
#ifdef __STDC__
#define XTextWidth(x,y,z) XmbTextEscapement(x ## set,y,z)
#else
#define XTextWidth(x,y,z) XmbTextEscapement(x/**/set,y,z)
#endif
#define XDrawString(t,u,v,w,x,y,z) XmbDrawString(t,u,ButtonFontset,v,w,x,y,z)
#endif
#define MAX_NO_ICON_ACTION_LENGTH (MAX_MODULE_INPUT_TEXT_LEN - 100)
#define GRAB_EVENTS (ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|EnterWindowMask|LeaveWindowMask)
#define COMPLEX_WINDOW_PLACEMENT
#define SomeButtonDown(a) ((a) & DEFAULT_ALL_BUTTONS_MASK)
/* File type information */
FILE *console;
fd_set_size_t fd_width;
int Fvwm_fd[2];
int x_fd;
/* X related things */
Display *dpy;
Window Root;
Window win;
int screen;
XSizeHints g_hints;
int g_hints_rc;
int fscreen;
rectangle screen_g;
Pixel back[MAX_COLOUR_SETS];
Pixel fore[MAX_COLOUR_SETS];
GC graph[MAX_COLOUR_SETS];
GC shadow[MAX_COLOUR_SETS];
GC hilite[MAX_COLOUR_SETS];
GC background[MAX_COLOUR_SETS];
Pixmap win_bg;
XFontStruct *ButtonFont;
#ifdef I18N_MB
XFontSet ButtonFontset;
#endif
int fontheight;
int buttonheight;
static Atom wm_del_win;
Atom MwmAtom = None;
/* Module related information */
char *Module;
int WindowState=0;
int win_width=5;
int win_height=5;
int win_grav;
int win_x;
int win_y;
int win_title;
#ifdef COMPLEX_WINDOW_PLACEMENT
int win_border_x=0;
int win_border_y=0;
#endif
int Clength;
int Transient=0;
int Pressed=0;
int ButPressed;
int Checked=0;
int MinWidth=DEFMINWIDTH;
int MaxWidth=DEFMAXWIDTH;
ButtonArray buttons;
List windows;
char *ClickAction[NUMBER_OF_BUTTONS] =
{
"Iconify -1,Raise",
"Iconify",
"Lower"
},
*EnterAction,
*BackColor[MAX_COLOUR_SETS] = { "white" },
*ForeColor[MAX_COLOUR_SETS] = { "black" },
*geometry="";
int colorset[MAX_COLOUR_SETS];
Pixmap pixmap[MAX_COLOUR_SETS];
char *font_string = "fixed";
Bool UseSkipList = False;
Bool Anchor = True;
Bool UseIconNames = False;
Bool LeftJustify = False;
Bool TruncateLeft = False;
Bool ShowFocus = True;
Bool Follow = False;
int ReliefWidth = 2;
long CurrentDesk = 0;
int ShowCurrentDesk = 0;
static RETSIGTYPE TerminateHandler(int sig);
static char *AnimCommand = NULL;
/***************************************************************************
* TerminateHandler - reentrant signal handler that ends the main event loop
***************************************************************************/
static RETSIGTYPE TerminateHandler(int sig)
{
/*
* This function might not return - it could "long-jump"
* right out, so we need to do everything we need to do
* BEFORE we call it ...
*/
fvwmSetTerminate(sig);
}
/******************************************************************************
Main - Setup the XConnection,request the window list and loop forever
Based on main() from FvwmIdent:
Copyright 1994, Robert Nation and Nobutaka Suzuki.
******************************************************************************/
int main(int argc, char **argv)
{
char *temp, *s;
#ifdef HAVE_SIGACTION
struct sigaction sigact;
#endif
int i;
short opt_num;
for (i = 3; i < NUMBER_OF_MOUSE_BUTTONS; i++)
{
ClickAction[i] = "Nop";
}
/* Save the program name for error messages and config parsing */
temp = argv[0];
s=strrchr(argv[0], '/');
if (s != NULL)
temp = s + 1;
/* Open the console for messages */
OpenConsole();
if((argc != 6)&&(argc != 7)&&(argc != 8)) {
fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",temp,
VERSION);
ConsoleMessage("%s Version %s should only be executed by fvwm!\n",temp,
VERSION);
exit(1);
}
opt_num = 6;
if (argc == 7 && (strcasecmp(argv[6],"Transient") == 0 ||
strcasecmp(argv[6],"-Transient") == 0))
{
Transient=1;
opt_num++;
}
/* Check for an alias */
if (argc >= opt_num + 1 && argv[opt_num] != NULL)
{
Module = safemalloc(strlen(argv[opt_num])+2);
strcpy(Module,"*");
strcat(Module, argv[opt_num]);
Clength = strlen(Module);
}
else
{
Module = safemalloc(strlen(temp)+2);
strcpy(Module,"*");
strcat(Module, temp);
Clength = strlen(Module);
}
#ifdef I18N_MB
setlocale(LC_CTYPE, "");
#endif
Fvwm_fd[0] = atoi(argv[1]);
Fvwm_fd[1] = atoi(argv[2]);
#ifdef HAVE_SIGACTION
#ifdef SA_INTERRUPT
sigact.sa_flags = SA_INTERRUPT;
#else
sigact.sa_flags = 0;
#endif
sigemptyset(&sigact.sa_mask);
sigaddset(&sigact.sa_mask, SIGTERM);
sigaddset(&sigact.sa_mask, SIGPIPE);
sigaddset(&sigact.sa_mask, SIGINT);
sigact.sa_handler = TerminateHandler;
sigaction(SIGPIPE, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
#else
#ifdef USE_BSD_SIGNALS
fvwmSetSignalMask( sigmask(SIGPIPE) |
sigmask(SIGINT) |
sigmask(SIGTERM) );
#endif
signal(SIGPIPE, TerminateHandler);
signal(SIGTERM, TerminateHandler);
signal(SIGINT, TerminateHandler);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGPIPE, True);
siginterrupt(SIGTERM, True);
siginterrupt(SIGINT, True);
#endif
#endif
/* set default colorsets */
colorset[0] = colorset[1] = 0;
colorset[2] = colorset[3] = 1;
AllocColorset(1);
/* Setup the XConnection */
StartMeUp_I();
/* Parse the config file */
ParseConfig();
/* more initialisations */
StartMeUp_II();
XSetErrorHandler(ErrorHandler);
InitArray(&buttons,0,0,win_width, fontheight+2, ReliefWidth);
InitList(&windows);
fd_width = GetFdWidth();
/* Request a list of all windows,
* wait for ConfigureWindow packets */
SetMessageMask(Fvwm_fd,
#ifdef MINI_ICONS
M_MINI_ICON |
#endif
M_CONFIGURE_WINDOW | M_ADD_WINDOW | M_DESTROY_WINDOW |
M_WINDOW_NAME | M_ICON_NAME | M_DEICONIFY | M_ICONIFY |
M_END_WINDOWLIST | M_NEW_DESK | M_FOCUS_CHANGE |
M_CONFIG_INFO | M_SENDCONFIG);
SendFvwmPipe(Fvwm_fd, "Send_WindowList",0);
/* Recieve all messages from Fvwm */
atexit(ShutMeDown);
/* tell fvwm we're running */
SendFinishedStartupNotification(Fvwm_fd);
/* Lock on send only for iconify and deiconify (for NoIconAction) */
SetSyncMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY);
SetNoGrabMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY);
MainEventLoop();
return 0;
}
/******************************************************************************
MainEventLoop - Read and redraw until we die, blocking when can't read
******************************************************************************/
void MainEventLoop(void)
{
fd_set readset;
while( !isTerminated ) {
FD_ZERO(&readset);
FD_SET(Fvwm_fd[1],&readset);
FD_SET(x_fd,&readset);
/* This code restyled after FvwmIconMan, which is simpler.
* The biggest advantage over the original approach is
* having one fewer select statements
*/
XFlush(dpy);
if (fvwmSelect(fd_width, &readset, NULL, NULL, NULL) > 0) {
if (FD_ISSET(x_fd,&readset) || XPending(dpy)) LoopOnEvents();
if (FD_ISSET(Fvwm_fd[1],&readset)) ReadFvwmPipe();
}
} /* while */
}
/******************************************************************************
ReadFvwmPipe - Read a single message from the pipe from Fvwm
Originally Loop() from FvwmIdent:
Copyright 1994, Robert Nation and Nobutaka Suzuki.
******************************************************************************/
void ReadFvwmPipe(void)
{
FvwmPacket* packet = ReadFvwmPacket(Fvwm_fd[1]);
if ( packet == NULL )
exit(0);
else
ProcessMessage( packet->type, packet->body );
}
/******************************************************************************
ProcessMessage - Process the message coming from Fvwm
Skeleton based on processmessage() from FvwmIdent:
Copyright 1994, Robert Nation and Nobutaka Suzuki.
******************************************************************************/
void ProcessMessage(unsigned long type,unsigned long *body)
{
int redraw=0,i,j;
Item *flagitem;
char *name,*string;
static int current_focus=-1;
struct ConfigWinPacket *cfgpacket;
#ifdef MINI_ICONS
Picture p;
#endif
switch(type)
{
case M_ADD_WINDOW:
case M_CONFIGURE_WINDOW:
cfgpacket = (void *) body;
/* We get the win_borders only when WinList map it self, this is ok
* since we need it only after an unmap */
#ifdef COMPLEX_WINDOW_PLACEMENT
if (cfgpacket->w == win)
{
win_border_x = win_border_y = cfgpacket->border_width;
if (((win_grav == NorthWestGravity || win_grav == NorthEastGravity)
&& !HAS_BOTTOM_TITLE(cfgpacket)) ||
((win_grav == SouthWestGravity || win_grav == SouthEastGravity)
&& HAS_BOTTOM_TITLE(cfgpacket)))
win_border_y += cfgpacket->title_height;
}
#endif
if ((i = FindItem(&windows,cfgpacket->w))!=-1)
{
flagitem=ItemFlags(&windows,cfgpacket->w);
if(UpdateItemDesk(&windows, cfgpacket) > 0 ||
IS_STICKY(cfgpacket) != IS_STICKY(flagitem) ||
DO_SKIP_WINDOW_LIST(cfgpacket) != DO_SKIP_WINDOW_LIST(flagitem))
{
UpdateItemGSFRFlags(&windows, cfgpacket);
UpdateButtonDeskFlags(&buttons, i, cfgpacket->desk,
IS_STICKY(cfgpacket),
DO_SKIP_WINDOW_LIST(cfgpacket));
AdjustWindow(False);
RedrawWindow(True, True);
}
else
UpdateItemGSFRFlags(&windows, cfgpacket);
break;
}
else
AddItem(&windows, cfgpacket);
break;
case M_DESTROY_WINDOW:
cfgpacket = (void *) body;
if ((i=DeleteItem(&windows,cfgpacket->w))==-1) break;
RemoveButton(&buttons,i);
if (WindowState)
AdjustWindow(False);
redraw=1;
break;
#ifdef MINI_ICONS
case M_MINI_ICON:
if ((i=FindItem(&windows,body[0]))==-1) break;
if (UpdateButton(&buttons,i,NULL,-1)!=-1)
{
p.width = body[3];
p.height = body[4];
p.depth = body[5];
p.picture = body[6];
p.mask = body[7];
UpdateButtonPicture(&buttons, i, &p);
AdjustWindow(False);
redraw = 1;
}
break;
#endif
case M_WINDOW_NAME:
case M_ICON_NAME:
if ((type == M_ICON_NAME) ^ UseIconNames)
break;
string=(char *)&body[3];
if ((i=UpdateItemName(&windows,body[0],string))==-1) break;
flagitem = ItemFlags(&windows,body[0]);
name=makename(string, (IS_ICONIFIED(flagitem)?True:False));
if (UpdateButton(&buttons,i,name,-1)==-1)
{
AddButton(&buttons, name, NULL, 1);
UpdateButtonSet(&buttons, i, (IS_ICONIFIED(flagitem)?1:0));
UpdateButtonDeskFlags(&buttons,i,ItemDesk(&windows, body[0]),
IS_STICKY(flagitem),
DO_SKIP_WINDOW_LIST(flagitem));
}
free(name);
if (WindowState) AdjustWindow(False);
redraw=1;
break;
case M_DEICONIFY:
case M_ICONIFY:
/* fwvm will wait for an Unlock message before continuing
* be careful when changing this construct, make sure unlock happens */
if ((i = FindItem(&windows, body[0])) != -1) {
flagitem = ItemFlags(&windows, body[0]);
if ((type == M_DEICONIFY && IS_ICONIFIED(flagitem))
|| (type == M_ICONIFY && !IS_ICONIFIED(flagitem))) {
if (IS_ICON_SUPPRESSED(flagitem) && IsItemIndexVisible(&windows,i)
&& AnimCommand && WindowState && AnimCommand[0] != 0) {
char buff[MAX_MODULE_INPUT_TEXT_LEN];
Window child;
int x, y;
/* find out where our button is */
j = FindItemVisible(&windows, body[0]);
XTranslateCoordinates(dpy, win, Root, 0, j * buttonheight,
&x, &y, &child);
/* tell FvwmAnimate to animate to our button */
if (IS_ICONIFIED(flagitem)) {
sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand,
x, y, win_width, buttonheight,
(int)body[7], (int)body[8], (int)body[9],
(int)body[10]);
} else {
sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand,
(int)body[7], (int)body[8], (int)body[9], (int)body[10],
x, y, win_width, buttonheight);
}
SendText(Fvwm_fd, buff, 0);
}
SET_ICONIFIED(flagitem, !IS_ICONIFIED(flagitem));
string = ItemName(&windows, i);
name = makename(string, IS_ICONIFIED(flagitem));
UpdateButtonIconified(&buttons, i, IS_ICONIFIED(flagitem));
if (UpdateButton(&buttons, i, name, -1) != -1) redraw = 1;
if (i != current_focus || (IS_ICONIFIED(flagitem)))
if (UpdateButtonSet(&buttons, i, (IS_ICONIFIED(flagitem)) ? 1 : 0)
!= -1)
redraw = 1;
free(name);
}
}
SendUnlockNotification(Fvwm_fd);
break;
case M_FOCUS_CHANGE:
redraw = 1;
if ((i=FindItem(&windows,body[0]))!=-1)
{
RadioButton(&buttons,i,ButPressed);
if (Follow && i) { /* rearrange order */
ReorderList(&windows,i,body[2]);
if (WindowState) ReorderButtons(&buttons,i,body[2]);
}
}
else
RadioButton(&buttons,-1,ButPressed);
break;
case M_END_WINDOWLIST:
if (!WindowState)
MakeMeWindow();
redraw = 1;
break;
case M_NEW_DESK:
CurrentDesk = body[0];
if(ShowCurrentDesk)
{
AdjustWindow(False);
RedrawWindow(True, True);
}
break;
case M_CONFIG_INFO:
ParseConfigLine((char *)&body[3]);
break;
}
if (redraw && WindowState==1) RedrawWindow(False, True);
}
/******************************************************************************
RedrawWindow - Update the needed lines and erase any old ones
******************************************************************************/
void RedrawWindow(Bool force, Bool clear_bg)
{
DrawButtonArray(&buttons, force, clear_bg);
XFlush(dpy); /** Put here for VMS; ifdef if causes performance problem **/
if (XQLength(dpy) && !force) LoopOnEvents();
}
/******************************************************************************
ConsoleMessage - Print a message on the console. Works like printf.
******************************************************************************/
void ConsoleMessage(const char *fmt, ...)
{
#ifndef NO_CONSOLE
va_list args;
FILE *filep;
if (console==NULL) filep=stderr;
else filep=console;
va_start(args,fmt);
vfprintf(filep,fmt,args);
va_end(args);
#endif
}
/******************************************************************************
OpenConsole - Open the console as a way of sending messages
******************************************************************************/
int OpenConsole(void)
{
#ifndef NO_CONSOLE
if ((console=fopen("/dev/console","w"))==NULL) {
fprintf(stderr,"%s: cannot open console\n",Module);
return 0;
}
#endif
return 1;
}
/******************************************************************************
ParseConfig - Parse the configuration file fvwm to us to use
Based on part of main() from FvwmIdent:
Copyright 1994, Robert Nation and Nobutaka Suzuki.
******************************************************************************/
void ParseConfig(void)
{
char *tline;
InitGetConfigLine(Fvwm_fd,Module);
GetConfigLine(Fvwm_fd,&tline);
while(tline != (char *)0)
{
ParseConfigLine(tline);
GetConfigLine(Fvwm_fd,&tline);
}
}
void
ParseConfigLine(char *tline)
{
static Bool has_icon_back = False;
static Bool has_icon_fore = False;
static Bool has_icon_cset = False;
if (!tline)
return;
if (strlen(tline) > 1) {
if (strncasecmp(tline, CatString3(Module, "Font", ""), Clength + 4) == 0)
CopyStringWithQuotes(&font_string, &tline[Clength + 4]);
else if (strncasecmp(tline, CatString3(Module, "Fore", ""), Clength + 4)
== 0) {
CopyString(&ForeColor[0], &tline[Clength + 4]);
colorset[0] = -1;
if (!has_icon_cset)
colorset[1] = -1;
if (!has_icon_fore)
CopyString(&ForeColor[1], &tline[Clength + 4]);
} else if (strncasecmp(tline, CatString3(Module, "IconFore", ""),
Clength + 8) == 0) {
CopyString(&ForeColor[1], &tline[Clength + 8]);
if (colorset[0] >= 0)
colorset[1] = colorset[0];
else
colorset[1] = -1;
has_icon_fore = True;
has_icon_cset = False;
} else if (strncasecmp(tline, CatString3(Module, "FocusFore", ""),
Clength + 9) == 0) {
CopyString(&ForeColor[2], &tline[Clength + 9]);
CopyString(&ForeColor[3], &tline[Clength + 9]);
colorset[2] = colorset[3] = -1;
} else if (strncasecmp(tline, CatString3(Module, "Geometry", ""),
Clength + 8) == 0)
CopyString(&geometry, &tline[Clength + 8]);
else if (strncasecmp(tline, CatString3(Module, "Back", ""), Clength + 4)
== 0) {
CopyString(&BackColor[0], &tline[Clength + 4]);
colorset[0] = -1;
if (!has_icon_cset)
colorset[1] = -1;
if (!has_icon_back)
CopyString(&BackColor[1], &tline[Clength + 4]);
} else if (strncasecmp(tline, CatString3(Module, "IconBack", ""),
Clength + 8) == 0) {
CopyString(&BackColor[1], &tline[Clength + 8]);
if (colorset[0] >= 0)
colorset[1] = colorset[0];
else
colorset[1] = -1;
has_icon_fore = True;
has_icon_cset = False;
} else if (strncasecmp(tline, CatString3(Module, "FocusBack", ""),
Clength + 9) == 0) {
CopyString(&BackColor[2], &tline[Clength + 9]);
CopyString(&BackColor[3], &tline[Clength + 9]);
colorset[2] = colorset[3] = -1;
} else if (strncasecmp(tline, CatString3(Module, "NoAnchor", ""),
Clength + 8) == 0)
Anchor = False;
else if (strncasecmp(tline, CatString3(Module, "Action", ""), Clength + 6)
== 0)
LinkAction(&tline[Clength + 6]);
else if (strncasecmp(tline, CatString3(Module, "UseSkipList", ""),
Clength + 11) == 0)
UseSkipList = True;
else if (strncasecmp(tline, CatString3(Module, "UseIconNames", ""),
Clength + 12) == 0)
UseIconNames = True;
else if (strncasecmp(tline, CatString3(Module, "ShowCurrentDesk", ""),
Clength + 15) == 0)
ShowCurrentDesk = 1;
else if (strncasecmp(tline, CatString3(Module, "LeftJustify", ""),
Clength + 11) == 0)
LeftJustify = True;
else if (strncasecmp(tline, CatString3(Module, "TruncateLeft", ""),
Clength + 12) == 0)
TruncateLeft = True;
else if (strncasecmp(tline, CatString3(Module, "MinWidth", ""),
Clength + 8) == 0)
MinWidth = atoi(&tline[Clength + 8]);
else if (strncasecmp(tline, CatString3(Module, "MaxWidth", ""),
Clength + 8) == 0)
MaxWidth = atoi(&tline[Clength + 8]);
else if (strncasecmp(tline, CatString3(Module, "DontDepressFocus", ""),
Clength + 16) == 0)
ShowFocus = False;
else if (strncasecmp(tline, CatString3(Module, "FollowWindowList", ""),
Clength + 16) == 0)
Follow = True;
else if (strncasecmp(tline, CatString3(Module, "ButtonFrameWidth", ""),
Clength + 16) == 0) {
ReliefWidth = atoi(&tline[Clength + 16]);
buttonheight = fontheight + 3 + 2 * ReliefWidth;
} else if (strncasecmp(tline, CatString3(Module, "NoIconAction", ""),
Clength + 12) == 0) {
CopyString(&AnimCommand, &tline[Clength + 12]);
if (strlen(AnimCommand) > MAX_NO_ICON_ACTION_LENGTH)
AnimCommand[MAX_NO_ICON_ACTION_LENGTH] = 0;
} else if (strncasecmp(tline, CatString3(Module, "Colorset", ""),
Clength + 8) == 0) {
colorset[0] = atoi(&tline[Clength + 8]);
AllocColorset(colorset[0]);
} else if (strncasecmp(tline, CatString3(Module, "IconColorset", ""),
Clength + 12) == 0)
{
colorset[1] = atoi(&tline[Clength + 12]);
AllocColorset(colorset[1]);
has_icon_cset = True;
}
else if (strncasecmp(tline, CatString3(Module, "FocusColorset", ""),
Clength + 13) == 0)
{
colorset[2] = colorset[3] = atoi(&tline[Clength + 13]);
AllocColorset(colorset[3]);
has_icon_cset = True;
}
else if (strncasecmp(tline, "Colorset", 8) == 0) {
int cset = LoadColorset(&tline[8]);
if (WindowState && (cset >= 0)) {
int i;
Pixmap old_win_bg = win_bg;
/* set the window background */
win_bg = None;
for (i = 0; i != MAX_COLOUR_SETS; i++)
if (colorset[i] >= 0 &&
Colorset[colorset[i]].pixmap == ParentRelative)
win_bg = ParentRelative;
if (old_win_bg != win_bg)
XSetWindowBackgroundPixmap(dpy, win, win_bg);
/* refresh if this colorset is used */
for (i = 0; i != MAX_COLOUR_SETS; i++) {
if (colorset[i] == cset) {
AdjustWindow(True);
RedrawWindow(True, True);
break;
}
}
}
}
else if (strncasecmp(tline, XINERAMA_CONFIG_STRING,
sizeof(XINERAMA_CONFIG_STRING) - 1) == 0) {
FScreenConfigureModule(
tline + sizeof(XINERAMA_CONFIG_STRING) - 1);
}
}
}
/******************************************************************************
LoopOnEvents - Process all the X events we get
******************************************************************************/
void LoopOnEvents(void)
{
int num;
char buffer[10];
XEvent Event;
#if 1
Window dummyroot,dummychild;
int x,x1,y,y1;
unsigned int dummy1;
if (Transient && !Checked)
{
if (Pressed)
{
XQueryPointer(dpy,win,&dummyroot,&dummychild,&x1,&y1,&x,&y,&dummy1);
num=WhichButton(&buttons,x,y);
if (num!=-1)
{
Pressed=1;
ButPressed=num;
UpdateButton(&buttons, num, NULL, 0);
}
else
{
Pressed=0;
}
}
Checked=1;
}
#endif
while(XPending(dpy))
{
XNextEvent(dpy,&Event);
switch(Event.type)
{
case ButtonRelease:
if (Pressed)
{
num=WhichButton(&buttons,Event.xbutton.x,Event.xbutton.y);
if (num!=-1 && Event.xbutton.button >= 1 &&
Event.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS)
{
SendFvwmPipe(Fvwm_fd,
ClickAction[Event.xbutton.button-1],
ItemID(&windows,num));
SwitchButton(&buttons,num);
}
}
if (Transient)
{
exit(0);
}
Pressed=0;
ButPressed=-1;
break;
case ButtonPress:
num=WhichButton(&buttons,Event.xbutton.x,Event.xbutton.y);
if (num != -1)
{
SwitchButton(&buttons,num);
ButPressed=num;
} else ButPressed=-1;
Pressed=1;
break;
case Expose:
/* have to clear each button with its background,
* let the server compute the intersections */
do
ExposeAllButtons(&buttons, &Event);
while (XCheckTypedWindowEvent(dpy, win, Expose, &Event));
/* No more expose events in the queue draw all icons,
* text and shadows, but not the background */
RedrawWindow(True, False);
break;
case ConfigureNotify:
{
XEvent event;
/* Opaque moves cause lots of these to be sent which causes flickering
* It's better to miss out on intermediate steps than to do them all
* and take too long. Look down the event queue and do the last one */
while (XCheckTypedWindowEvent(dpy, win, ConfigureNotify, &event))
{
/* if send_event is true it means the user has moved the window or
* winlist has mapped itself, take note of the new position.
* If it is false it comes from the Xserver and is bogus */
if (!event.xconfigure.send_event)
continue;
Event.xconfigure.x = event.xconfigure.x;
Event.xconfigure.y = event.xconfigure.y;
Event.xconfigure.send_event = True;
}
}
if (Event.xconfigure.send_event && (win_x != Event.xconfigure.x
|| win_y != Event.xconfigure.y)) {
win_x = Event.xconfigure.x;
win_y = Event.xconfigure.y;
if (win_bg == ParentRelative)
RedrawWindow(True, True);
}
break;
case KeyPress:
num=XLookupString(&Event.xkey,buffer,10,NULL,0);
if (num==1)
{
if (buffer[0]=='q' || buffer[0]=='Q') exit(0);
else if (buffer[0]=='i' || buffer[0]=='I') PrintList(&windows);
else if (buffer[0]=='b' || buffer[0]=='B') PrintButtons(&buttons);
}
break;
case ClientMessage:
if ((Event.xclient.format==32) && (Event.xclient.data.l[0]==wm_del_win))
exit(0);
case EnterNotify:
if (!SomeButtonDown(Event.xcrossing.state)) break;
num=WhichButton(&buttons,Event.xcrossing.x,Event.xcrossing.y);
if (num!=-1)
{
SwitchButton(&buttons,num);
ButPressed=num;
} else ButPressed=-1;
Pressed=1;
break;
case LeaveNotify:
if (!SomeButtonDown(Event.xcrossing.state)) break;
if (ButPressed!=-1) SwitchButton(&buttons,ButPressed);
Pressed=0;
break;
case MotionNotify:
if (!Pressed) break;
num=WhichButton(&buttons,Event.xmotion.x,Event.xmotion.y);
if (num==ButPressed) break;
if (ButPressed!=-1) SwitchButton(&buttons,ButPressed);
if (num!=-1)
{
SwitchButton(&buttons,num);
ButPressed=num;
}
else ButPressed=-1;
break;
}
}
}
/******************************************************************************
AdjustWindow - Resize the window according to maxwidth by number of buttons
******************************************************************************/
void AdjustWindow(Bool force)
{
int new_width=0,new_height=0,tw,i,total,all;
char *temp;
#ifdef MINI_ICONS
int base_miw = 0;
#endif
total = ItemCountVisible(&windows);
all = ItemCount(&windows);
if (!total)
{
if (WindowState==1)
{
XUnmapWindow(dpy,win);
WindowState=2;
}
return;
}
#ifdef MINI_ICONS
for(i=0; i<all; i++)
{
if(IsButtonIndexVisible(&buttons,i) &&
ButtonPicture(&buttons,i)->picture != None)
{
if (ButtonPicture(&buttons,i)->width > base_miw)
base_miw = ButtonPicture(&buttons,i)->width;
break;
}
}
base_miw += 2;
#endif
for(i=0;i<all;i++)
{
temp=ItemName(&windows,i);
if(temp != NULL && IsItemIndexVisible(&windows,i))
{
tw = 8 + XTextWidth(ButtonFont,temp,strlen(temp));
tw += XTextWidth(ButtonFont,"()",2);
#ifdef MINI_ICONS
tw += base_miw;
#endif
new_width=max(new_width,tw);
}
}
new_width=max(new_width, MinWidth);
new_width=min(new_width, MaxWidth);
new_height=(total * buttonheight);
if (WindowState && force) {
for (i = 0; i != MAX_COLOUR_SETS; i++) {
int cset = colorset[i];
if (cset >= 0) {
fore[i] = Colorset[cset].fg;
back[i] = Colorset[cset].bg;
XSetForeground(dpy, graph[i], fore[i]);
XSetForeground(dpy, background[i], back[i]);
XSetForeground(dpy, hilite[i], Colorset[cset].hilite);
XSetForeground(dpy, shadow[i], Colorset[cset].shadow);
}
}
}
/* change the pixmap if forced or if width changed (the height is fixed) */
if (WindowState && (force || new_width != win_width)) {
for (i = 0; i != MAX_COLOUR_SETS; i++) {
int cset = colorset[i];
if (cset >= 0) {
if (pixmap[i])
XFreePixmap(dpy, pixmap[i]);
if (Colorset[cset].pixmap) {
pixmap[i] = CreateBackgroundPixmap(dpy, win, new_width, buttonheight,
&Colorset[cset], Pdepth,
background[i], False);
XSetTile(dpy, background[i], pixmap[i]);
XSetFillStyle(dpy, background[i], FillTiled);
} else {
pixmap[i] = None;
XSetFillStyle(dpy, background[i], FillSolid);
}
}
}
}
if (WindowState && (new_height!=win_height || new_width!=win_width))
{
#ifdef COMPLEX_WINDOW_PLACEMENT
if (Anchor)
{
/* compensate for fvwm borders when going from unmapped to mapped */
int map_x_adjust = (WindowState - 1) * win_border_x;
int map_y_adjust = (WindowState - 1) * win_border_y;
switch (win_grav) {
case NorthWestGravity:
case SouthWestGravity:
win_x -= map_x_adjust;
break;
case NorthEastGravity:
case SouthEastGravity:
win_x += win_width - new_width + map_x_adjust;
break;
}
switch (win_grav) {
case NorthWestGravity:
case NorthEastGravity:
win_y -= map_y_adjust;
break;
case SouthEastGravity:
case SouthWestGravity:
win_y += win_height - new_height + map_y_adjust;
break;
}
/* XMoveResizeWindow(dpy, win, win_x, win_y, new_width, new_height); */
}
if (Anchor && WindowState == 2)
XMoveResizeWindow(dpy, win, win_x, win_y, new_width, new_height);
else
XResizeWindow(dpy, win, new_width, new_height);
/* The new code is sooo much simpler :-) */
#else
/* This relies on fvwm honouring South/East gemoetry when resizing. */
XResizeWindow(dpy, win, new_width, new_height);
#endif
}
UpdateArray(&buttons,new_width);
if (new_height>0) win_height = new_height;
if (new_width>0) win_width = new_width;
if (WindowState==2)
{
XMapWindow(dpy,win);
WindowState=1;
}
}
/******************************************************************************
makename - Based on the flags return me '(name)' or 'name'
******************************************************************************/
char *makename(const char *string, Bool iconified)
{
char *ptr;
if (!iconified)
return safestrdup(string);
ptr=safemalloc(strlen(string)+3);
sprintf(ptr, "(%s)", string);
return ptr;
}
/******************************************************************************
LinkAction - Link an response to a users action
******************************************************************************/
void LinkAction(char *string)
{
char *temp;
temp=string;
while(isspace((unsigned char)*temp))
temp++;
if(strncasecmp(temp, "Click", 5)==0)
{
int n;
int b;
int i;
i = sscanf(temp + 5, "%d%n", &b, &n);
if (i > 0 && b >=1 && b <= NUMBER_OF_MOUSE_BUTTONS)
{
CopyString(&ClickAction[b - 1], temp + 5 + n);
}
}
else if(strncasecmp(temp, "Enter", 5)==0)
CopyString(&EnterAction,&temp[5]);
}
/******************************************************************************
MakeMeWindow - Create and setup the window we will need
******************************************************************************/
void MakeMeWindow(void)
{
XSizeHints hints;
XClassHint classhints;
XGCValues gcval;
unsigned long gcmask;
unsigned int dummy1, dummy2;
int x, y, ret, count;
Window dummyroot, dummychild;
int i;
XSetWindowAttributes attr;
if ((count = ItemCountVisible(&windows))==0 && Transient)
{
exit(0);
}
AdjustWindow(False);
hints.width=win_width;
hints.height=win_height;
hints.win_gravity=NorthWestGravity;
hints.flags=PSize|PWinGravity;
if (Transient)
{
fscreen_scr_arg fscr;
XQueryPointer(dpy,Root,&dummyroot,&dummychild,&hints.x,&hints.y,&x,&y,
&dummy1);
fscr.xypos.x = hints.x;
fscr.xypos.y = hints.y;
FScreenGetScrRect(
&fscr, FSCREEN_XYPOS,
&screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height);
hints.x -= hints.width / 2;
hints.y -= buttonheight / 2;
if (hints.x + hints.width > screen_g.x + screen_g.width)
{
hints.x = screen_g.x + screen_g.width - hints.width;
}
if (hints.x < screen_g.x)
{
hints.x = screen_g.x;
}
if (hints.y + hints.height > screen_g.y + screen_g.height)
{
hints.y = screen_g.y + screen_g.height - hints.height;
}
if (hints.y < screen_g.y)
{
hints.y = screen_g.y;
}
hints.win_gravity = NorthWestGravity;
hints.flags |= USPosition;
}
else if (geometry!= NULL)
{
/* now evaluate the geometry parsed above */
ret = FScreenParseGeometry(geometry, &x, &y, &dummy1, &dummy2);
hints.win_gravity=NorthWestGravity;
if ((ret & XValue) && (ret & YValue))
{
hints.x = x;
hints.y = y;
if (ret & XNegative)
{
hints.x += XDisplayWidth(dpy,screen) - win_width;
hints.win_gravity=NorthEastGravity;
}
if (ret & YNegative)
{
hints.y += XDisplayHeight(dpy,screen) - win_height;
if (ret & XNegative)
{
hints.win_gravity=SouthEastGravity;
}
else
{
hints.win_gravity=SouthWestGravity;
}
}
hints.flags |= USPosition;
}
#ifndef COMPLEX_WINDOW_PLACEMENT
if (!Anchor)
{
if (hints.win_gravity == SouthWestGravity)
hints.win_gravity=NorthWestGravity;
else if (hints.win_gravity == SouthEastGravity)
hints.win_gravity=NorthEastGravity;
}
#endif
}
win_x = hints.x;
win_y = hints.y;
win_grav = hints.win_gravity;
for (i = 0; i != MAX_COLOUR_SETS; i++)
if(Pdepth < 2)
{
back[i] = GetColor("white");
fore[i] = GetColor("black");
}
else
{
if (colorset[i] >= 0) {
back[i] = Colorset[colorset[i]].bg;
fore[i] = Colorset[colorset[i]].fg;
} else {
back[i] = GetColor(BackColor[i] == NULL ? BackColor[0] : BackColor[i]);
fore[i] = GetColor(ForeColor[i] == NULL ? ForeColor[0] : ForeColor[i]);
}
}
/* FvwmWinList paints the entire window and does not rely on the xserver to
* render the background. Setting the background_pixmap to None prevents the
* server from doing anything on expose events. The exception is when one of
* the colorsets is transparent which requires help from the server */
win_bg = None;
for (i = 0; i != MAX_COLOUR_SETS; i++)
if (colorset[i] >= 0 && Colorset[colorset[i]].pixmap == ParentRelative)
{
win_bg = ParentRelative;
break;
}
attr.background_pixmap = win_bg;
attr.border_pixel = 0;
attr.colormap = Pcmap;
win=XCreateWindow(dpy, Root, hints.x, hints.y, hints.width, hints.height, 0,
Pdepth, InputOutput, Pvisual,
CWBackPixmap | CWBorderPixel | CWColormap, &attr);
if (Transient)
{
XSetTransientForHint(dpy, win, Root);
}
wm_del_win=XInternAtom(dpy,"WM_DELETE_WINDOW",False);
XSetWMProtocols(dpy,win,&wm_del_win,1);
{
XTextProperty nametext;
char *list[]={NULL,NULL};
list[0] = Module+1;
classhints.res_name=safestrdup(Module+1);
classhints.res_class=safestrdup("FvwmWinList");
if(!XStringListToTextProperty(list,1,&nametext))
{
fprintf(stderr,"%s: Failed to convert name to XText\n",Module);
exit(1);
}
XSetWMProperties(dpy,win,&nametext,&nametext,
NULL,0,&hints,NULL,&classhints);
XFree(nametext.value);
}
if (!Transient)
{
XGrabButton(dpy,1,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync,
GrabModeAsync,None,None);
XGrabButton(dpy,2,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync,
GrabModeAsync,None,None);
XGrabButton(dpy,3,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync,
GrabModeAsync,None,None);
SetMwmHints(
MWM_DECOR_ALL|MWM_DECOR_RESIZEH|MWM_DECOR_MAXIMIZE|MWM_DECOR_MINIMIZE,
MWM_FUNC_ALL|MWM_FUNC_RESIZE|MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE,
MWM_INPUT_MODELESS);
}
else
{
SetMwmHints(0,MWM_FUNC_ALL,MWM_INPUT_MODELESS);
}
for (i = 0; i != MAX_COLOUR_SETS; i++)
{
gcval.foreground=fore[i];
gcval.background=back[i];
gcval.font=ButtonFont->fid;
gcmask=GCForeground|GCBackground|GCFont;
graph[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval);
if(Pdepth < 2)
gcval.foreground=GetShadow(fore[i]);
else
if (colorset[i] < 0)
gcval.foreground=GetShadow(back[i]);
else
gcval.foreground=Colorset[colorset[i]].shadow;
gcval.background=back[i];
gcmask=GCForeground|GCBackground;
shadow[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval);
if (colorset[i] < 0)
gcval.foreground=GetHilite(back[i]);
else
gcval.foreground=Colorset[colorset[i]].hilite;
gcval.background=back[i];
gcmask=GCForeground|GCBackground;
hilite[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval);
gcval.foreground=back[i];
gcmask=GCForeground;
background[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval);
if ((colorset[i] >= 0) && Colorset[colorset[i]].pixmap
&& Colorset[colorset[i]].pixmap != ParentRelative) {
pixmap[i] = CreateBackgroundPixmap(dpy, win, win_width, buttonheight,
&Colorset[colorset[i]], Pdepth,
background[i], False);
XSetTile(dpy, background[i], pixmap[i]);
XSetFillStyle(dpy, background[i], FillTiled);
}
}
AdjustWindow(True);
XSelectInput(dpy,win,(StructureNotifyMask | ExposureMask | KeyPressMask));
if (ItemCountVisible(&windows) > 0)
{
XMapRaised(dpy,win);
WindowState=1;
} else WindowState=2;
if (Transient)
{
int i = 0;
XSync(dpy,0);
while (i < 1000 &&
XGrabPointer(dpy, win, True,
ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
PointerMotionMask|EnterWindowMask|LeaveWindowMask,
GrabModeAsync, GrabModeAsync, None,
None, CurrentTime) != GrabSuccess)
{
i++;
/* If you go too fast, other windows may not get a change to release
* any grab that they have. */
usleep(1000);
}
XSync(dpy,0);
if (i >= 1000)
{
fprintf(stderr,"failed to grab pointer\n");
exit(1);
}
XQueryPointer(
dpy,Root,&dummyroot,&dummychild,&hints.x,&hints.y,&x,&y,&dummy1);
Pressed = !!SomeButtonDown(dummy1);
}
}
/******************************************************************************
StartMeUp - Do X initialization things
******************************************************************************/
void StartMeUp_I(void)
{
if (!(dpy = XOpenDisplay("")))
{
fprintf(stderr,"%s: can't open display %s", Module,
XDisplayName(""));
exit (1);
}
InitPictureCMap(dpy);
FScreenInit(dpy);
AllocColorset(0);
FShapeInit(dpy);
x_fd = XConnectionNumber(dpy);
screen= DefaultScreen(dpy);
Root = RootWindow(dpy, screen);
return;
}
void StartMeUp_II(void)
{
#ifdef I18N_MB
char **ml;
int mc;
char *ds;
XFontStruct **fs_list;
#endif
if (geometry == NULL)
UpdateString(&geometry, "");
/* evaluate further down */
g_hints_rc = FScreenParseGeometryWithScreen(
geometry, &g_hints.x, &g_hints.y, (unsigned int *)&g_hints.width,
(unsigned int *)&g_hints.height, &fscreen);
FScreenGetScrRect(
NULL, fscreen, &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height);
#ifdef I18N_MB
if ((ButtonFontset=XCreateFontSet(dpy,font_string,&ml,&mc,&ds)) == NULL) {
#ifdef STRICTLY_FIXED
if ((ButtonFontset=XCreateFontSet(dpy,"fixed",&ml,&mc,&ds)) == NULL)
{
exit(1);
}
#else
if ((ButtonFontset=XCreateFontSet(dpy,"-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*",&ml,&mc,&ds)) == NULL)
{
exit(1);
}
#endif
}
XFontsOfFontSet(ButtonFontset,&fs_list,&ml);
ButtonFont = fs_list[0];
#else
if ((ButtonFont=XLoadQueryFont(dpy,font_string))==NULL)
{
if ((ButtonFont=XLoadQueryFont(dpy,"fixed"))==NULL)
{
exit(1);
}
}
#endif
fontheight = ButtonFont->ascent+ButtonFont->descent;
buttonheight = fontheight + 3 + 2 * ReliefWidth;
win_width=XTextWidth(ButtonFont,"XXXXXXXXXXXXXXX",10);
}
/******************************************************************************
ShutMeDown - Do X client cleanup
******************************************************************************/
void ShutMeDown(void)
{
FreeList(&windows);
FreeAllButtons(&buttons);
/* XFreeGC(dpy,graph);*/
if (WindowState) XDestroyWindow(dpy,win);
XCloseDisplay(dpy);
}
/******************************************************************************
ChangeWindowName - Self explanitory
Original work from FvwmIdent:
Copyright 1994, Robert Nation and Nobutaka Suzuki.
******************************************************************************/
void ChangeWindowName(char *str)
{
XTextProperty name;
if (XStringListToTextProperty(&str,1,&name) == 0) {
fprintf(stderr,"%s: cannot allocate window name.\n",Module);
return;
}
XSetWMName(dpy,win,&name);
XSetWMIconName(dpy,win,&name);
XFree(name.value);
}
/**************************************************************************
*
* Sets mwm hints
*
*************************************************************************/
/*
* Now, if we (hopefully) have MWW - compatible window manager ,
* say, mwm, ncdwm, or else, we will set useful decoration style.
* Never check for MWM_RUNNING property.May be considered bad.
*/
void SetMwmHints(unsigned int value, unsigned int funcs, unsigned int input)
{
PropMwmHints prop;
if (MwmAtom==None)
{
MwmAtom=XInternAtom(dpy,"_MOTIF_WM_HINTS",False);
}
if (MwmAtom!=None)
{
/* sh->mwm.decorations contains OR of the MWM_DECOR_XXXXX */
prop.decorations= value;
prop.functions = funcs;
prop.inputMode = input;
prop.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS |
MWM_HINTS_INPUT_MODE;
/* HOP - LA! */
XChangeProperty (dpy,win,
MwmAtom, MwmAtom,
32, PropModeReplace,
(unsigned char *)&prop,
PROP_MWM_HINTS_ELEMENTS);
}
}
/************************************************************************
X Error Handler
************************************************************************/
int ErrorHandler(Display *d, XErrorEvent *event)
{
/* some errors are OK=ish */
if (event->error_code == BadPixmap)
return 0;
if (event->error_code == BadDrawable)
return 0;
PrintXErrorAndCoredump(d, event, Module);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1