1438 lines
40 KiB
C
1438 lines
40 KiB
C
/* FvwmTaskBar Module for Fvwm.
|
|
*
|
|
* (Much reworked version of FvwmWinList)
|
|
* Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or
|
|
* Mike_Finger@atk.com)
|
|
* Minor hack by TKP to enable autohide to work with pages (leaves 2 pixels
|
|
* visible so that the 1 pixel panframes don't get in the way)
|
|
*
|
|
* 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 applicable 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, original 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. */
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <stdarg.h>
|
|
|
|
#if HAVE_SYS_SELECT_H
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
#ifdef HAVE_SYS_BSDTYPES_H
|
|
#include <sys/bsdtypes.h> /* Saul */
|
|
#endif /* Saul */
|
|
|
|
#include <stdlib.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/cursorfont.h>
|
|
|
|
#include "../../fvwm/module.h"
|
|
#include "../../libs/fvwmlib.h" /* for pixmaps routines */
|
|
|
|
|
|
#include "FvwmTaskBar.h"
|
|
#include "ButtonArray.h"
|
|
#include "List.h"
|
|
#include "Colors.h"
|
|
#include "Mallocs.h"
|
|
#include "Goodies.h"
|
|
#include "Start.h"
|
|
|
|
|
|
#define GRAB_EVENTS (ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|EnterWindowMask|LeaveWindowMask)
|
|
#define SomeButtonDown(a) ((a)&Button1Mask||(a)&Button2Mask||(a)&Button3Mask)
|
|
|
|
#define DEFAULT_CLICK1 "Iconify -1, Raise, Focus"
|
|
#define DEFAULT_CLICK2 "Iconify +1, Lower"
|
|
#define DEFAULT_CLICK3 "Nop"
|
|
|
|
#define gray_width 8
|
|
#define gray_height 8
|
|
unsigned char gray_bits[] = { 0xaa, 0x55, 0xaa, 0x55,
|
|
0xaa, 0x55, 0xaa, 0x55 };
|
|
GC checkered;
|
|
|
|
/* File type information */
|
|
FILE *console;
|
|
int fd_width;
|
|
int Fvwm_fd[2];
|
|
int x_fd;
|
|
|
|
/* X related things */
|
|
Display *dpy;
|
|
Window Root, win;
|
|
int screen, d_depth;
|
|
Pixel back, fore;
|
|
GC graph, shadow, hilite, blackgc, whitegc;
|
|
XFontStruct *ButtonFont, *SelButtonFont;
|
|
int fontheight;
|
|
static Atom wm_del_win;
|
|
Atom MwmAtom = None;
|
|
|
|
/* Module related information */
|
|
char *Module;
|
|
int win_width = 5,
|
|
win_height = 5,
|
|
win_grav,
|
|
win_x,
|
|
win_y,
|
|
win_border,
|
|
button_width = DEFAULT_BTN_WIDTH,
|
|
Clength,
|
|
ButPressed = -1,
|
|
ButReleased = -1,
|
|
Checked = 0,
|
|
BelayHide = False,
|
|
AlarmSet = NOT_SET;
|
|
|
|
int UpdateInterval = 30;
|
|
|
|
ButtonArray buttons;
|
|
List windows;
|
|
List swallowed;
|
|
|
|
char *ClickAction[3] = { DEFAULT_CLICK1, DEFAULT_CLICK2, DEFAULT_CLICK3 },
|
|
*EnterAction,
|
|
*BackColor = "white",
|
|
*ForeColor = "black",
|
|
*geometry = NULL,
|
|
*font_string = "fixed",
|
|
*selfont_string = NULL;
|
|
|
|
int UseSkipList = False,
|
|
UseIconNames = False,
|
|
ShowTransients = False,
|
|
adjust_flag = False,
|
|
AutoStick = False,
|
|
AutoHide = False,
|
|
HighlightFocus = False;
|
|
|
|
unsigned int ScreenWidth, ScreenHeight;
|
|
|
|
int NRows, RowHeight, Midline;
|
|
|
|
/* Imported from Goodies */
|
|
extern int stwin_width, goodies_width;
|
|
extern TipStruct Tip;
|
|
|
|
/* Imported from Start */
|
|
extern int StartButtonWidth, StartButtonHeight;
|
|
extern char *StartPopup;
|
|
|
|
Colormap PictureCMap;
|
|
|
|
char *IconPath = NULL,
|
|
*PixmapPath = NULL;
|
|
|
|
static void ParseConfigLine(char *tline);
|
|
|
|
/******************************************************************************
|
|
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;
|
|
|
|
/* Save the program name for error messages and config parsing */
|
|
temp = argv[0];
|
|
s=strrchr(argv[0], '/');
|
|
if (s != NULL)
|
|
temp = s + 1;
|
|
|
|
/* Setup my name */
|
|
Module = safemalloc(strlen(temp)+2);
|
|
strcpy(Module,"*");
|
|
strcat(Module, temp);
|
|
Clength = strlen(Module);
|
|
|
|
/* Open the console for messages */
|
|
OpenConsole();
|
|
|
|
if((argc != 6)&&(argc != 7)) {
|
|
fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",Module,
|
|
VERSION);
|
|
ConsoleMessage("%s Version %s should only be executed by fvwm!\n",Module,
|
|
VERSION);
|
|
exit(1);
|
|
}
|
|
|
|
/* setup fvwm pipes */
|
|
Fvwm_fd[0] = atoi(argv[1]);
|
|
Fvwm_fd[1] = atoi(argv[2]);
|
|
fd_width = GetFdWidth();
|
|
|
|
signal (SIGPIPE, DeadPipe);
|
|
signal (SIGALRM, Alarm);
|
|
|
|
SetMessageMask(Fvwm_fd,M_ADD_WINDOW | M_CONFIGURE_WINDOW | M_DESTROY_WINDOW |
|
|
M_WINDOW_NAME | M_ICON_NAME | M_RES_NAME | M_DEICONIFY | M_ICONIFY |
|
|
M_END_WINDOWLIST | M_FOCUS_CHANGE |
|
|
M_CONFIG_INFO | M_END_CONFIG_INFO
|
|
#ifdef FVWM95
|
|
| M_FUNCTION_END |
|
|
M_SCROLLREGION
|
|
#endif
|
|
#ifdef MINI_ICONS
|
|
| M_MINI_ICON
|
|
#endif
|
|
);
|
|
|
|
/* Parse the config file */
|
|
InitList(&swallowed);
|
|
|
|
ParseConfig();
|
|
|
|
/* Setup the XConnection */
|
|
StartMeUp();
|
|
XSetErrorHandler((XErrorHandler) ErrorHandler);
|
|
|
|
InitPictureCMap(dpy, Root);
|
|
|
|
StartButtonInit(RowHeight);
|
|
|
|
/* init the array of buttons */
|
|
InitArray(&buttons, StartButtonWidth + 4, 0,
|
|
win_width - stwin_width - 8 - StartButtonWidth -10,
|
|
RowHeight, button_width);
|
|
InitList(&windows);
|
|
|
|
/* Request a list of all windows,
|
|
* wait for ConfigureWindow packets */
|
|
SendFvwmPipe("Send_WindowList",0);
|
|
|
|
/* Receive all messages from Fvwm */
|
|
EndLessLoop();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
EndLessLoop - Read and redraw until we get killed, blocking when can't read
|
|
******************************************************************************/
|
|
void EndLessLoop()
|
|
{
|
|
fd_set readset;
|
|
struct timeval tv;
|
|
|
|
while(1) {
|
|
FD_ZERO(&readset);
|
|
FD_SET(Fvwm_fd[1], &readset);
|
|
FD_SET(x_fd, &readset);
|
|
XPending(dpy);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
if (!select(fd_width, SELECT_TYPE_ARG234 &readset, NULL, NULL, &tv)) {
|
|
while(1) {
|
|
FD_ZERO(&readset);
|
|
FD_SET(Fvwm_fd[1], &readset);
|
|
FD_SET(x_fd, &readset);
|
|
XPending(dpy);
|
|
tv.tv_sec = UpdateInterval;
|
|
tv.tv_usec = 0;
|
|
if (select(fd_width, SELECT_TYPE_ARG234 &readset, NULL, NULL, &tv)
|
|
<= 0)
|
|
DrawGoodies();
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(x_fd, &readset))
|
|
LoopOnEvents();
|
|
|
|
if (FD_ISSET(Fvwm_fd[1], &readset)) {
|
|
ReadFvwmPipe();
|
|
DrawGoodies();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
ReadFvwmPipe - Read a single message from the pipe from Fvwm
|
|
Originally Loop() from FvwmIdent:
|
|
Copyright 1994, Robert Nation and Nobutaka Suzuki.
|
|
******************************************************************************/
|
|
void ReadFvwmPipe()
|
|
{
|
|
unsigned long header[HEADER_SIZE],*body;
|
|
|
|
if(ReadFvwmPacket(Fvwm_fd[1],header,&body) > 0)
|
|
{
|
|
ProcessMessage(header[1],body);
|
|
free(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=-1;
|
|
int i;
|
|
long flags;
|
|
char *string;
|
|
Picture p;
|
|
|
|
switch(type) {
|
|
case M_FOCUS_CHANGE:
|
|
i = FindItem(&windows, body[0]);
|
|
if (win != body[0]) { /* This case is handled in LoopOnEvents() */
|
|
if (ItemFlags(&windows, body[0]) & ICONIFIED) i = -1;
|
|
RadioButton(&buttons, i, BUTTON_BRIGHT);
|
|
ButPressed = i;
|
|
ButReleased = -1;
|
|
redraw = 0;
|
|
}
|
|
break;
|
|
|
|
case M_ADD_WINDOW:
|
|
case M_CONFIGURE_WINDOW:
|
|
/* Matched only at startup when default border width and
|
|
actual border width differ. Don't assign win_width here so
|
|
Window redraw and rewarping gets handled by XEvent
|
|
ConfigureNotify code. */
|
|
if (!ShowTransients && (body[8] & TRANSIENT)) break;
|
|
if (body[0] == win) {
|
|
if (win_border != (int)body[10]) {
|
|
win_x = win_border = (int)body[10];
|
|
|
|
if (win_y > Midline)
|
|
win_y = ScreenHeight - (AutoHide ? 2 : win_height + win_border);
|
|
else
|
|
win_y = AutoHide ? 2 - win_height : win_border;
|
|
|
|
XMoveResizeWindow(dpy, win, win_x, win_y,
|
|
ScreenWidth-(win_border<<1), win_height);
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (FindItem(&windows,body[0]) != -1) break;
|
|
if (!(body[8] & WINDOWLISTSKIP) || !UseSkipList) {
|
|
AddItem(&windows, body[0], body[8]);
|
|
}
|
|
break;
|
|
|
|
case M_DESTROY_WINDOW:
|
|
if ((i = DeleteItem(&windows, body[0])) == -1) break;
|
|
if (FindItem(&swallowed, body[0]) != -1) break;
|
|
RemoveButton(&buttons, i);
|
|
redraw = 1;
|
|
break;
|
|
|
|
#ifdef MINI_ICONS
|
|
case M_MINI_ICON:
|
|
if ((i = FindItem(&windows, body[0])) == -1) break;
|
|
if (UpdateButton(&buttons, i, NULL, DONT_CARE) != -1) {
|
|
p.picture = body[6];
|
|
p.mask = body[7];
|
|
p.width = body[3];
|
|
p.height = body[4];
|
|
p.depth = body[5];
|
|
UpdateButtonPicture(&buttons, i, &p);
|
|
redraw = 0;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case M_WINDOW_NAME:
|
|
case M_ICON_NAME:
|
|
if ((type == M_ICON_NAME && !UseIconNames) ||
|
|
(type == M_WINDOW_NAME && UseIconNames)) break;
|
|
string = (char *) &body[3];
|
|
if ((i = FindNameItem(&swallowed, string)) != -1) {
|
|
if (ItemIndexFlags(&swallowed, i) == F_NOT_SWALLOWED) {
|
|
Swallow(body);
|
|
break;
|
|
}
|
|
}
|
|
if ((i = UpdateItemName(&windows, body[0], (char *)&body[3])) == -1)
|
|
break;
|
|
if (UpdateButton(&buttons, i, string, DONT_CARE) == -1)
|
|
{
|
|
AddButton(&buttons, string, NULL, BUTTON_UP);
|
|
redraw = 1;
|
|
}
|
|
else
|
|
redraw = 0;
|
|
break;
|
|
|
|
case M_DEICONIFY:
|
|
case M_ICONIFY:
|
|
if ((i = FindItem(&windows, body[0])) == -1) break;
|
|
flags = ItemFlags(&windows, body[0]);
|
|
if (type == M_DEICONIFY && !(flags & ICONIFIED)) break;
|
|
if (type == M_ICONIFY && flags & ICONIFIED) break;
|
|
flags ^= ICONIFIED;
|
|
if (type == M_ICONIFY && i == ButReleased) {
|
|
RadioButton(&buttons, -1, BUTTON_UP);
|
|
ButReleased = ButPressed = -1;
|
|
redraw = 0;
|
|
}
|
|
UpdateItemFlags(&windows, body[0], flags);
|
|
break;
|
|
|
|
case M_END_WINDOWLIST:
|
|
XMapRaised(dpy, win);
|
|
break;
|
|
|
|
#ifdef FVWM95
|
|
case M_FUNCTION_END:
|
|
StartButtonUpdate(NULL, BUTTON_UP);
|
|
|
|
if (AutoHide && !BelayHide) /* We don't want the taskbar to hide */
|
|
SetAlarm(HIDE_TASK_BAR); /* after a Focus or Iconify function */
|
|
|
|
redraw = 0;
|
|
break;
|
|
|
|
/* Added a new Fvwm Event because scrolling regions interfere
|
|
with EnterNotify event when taskbar is hidden. */
|
|
case M_SCROLLREGION:
|
|
if (AutoHide && ((win_y < Midline && body[1] < 4) ||
|
|
(win_y >= Midline && body[1] > ScreenHeight-4)))
|
|
RevealTaskBar();
|
|
break;
|
|
|
|
#endif /*FVWM95*/
|
|
|
|
case M_NEW_DESK:
|
|
break;
|
|
|
|
case M_NEW_PAGE:
|
|
break;
|
|
|
|
}
|
|
|
|
if (redraw >= 0) RedrawWindow(redraw);
|
|
}
|
|
|
|
/******************************************************************************
|
|
SendFvwmPipe - Send a message back to fvwm
|
|
Based on SendInfo() from FvwmIdent:
|
|
Copyright 1994, Robert Nation and Nobutaka Suzuki.
|
|
******************************************************************************/
|
|
void SendFvwmPipe(char *message, unsigned long window)
|
|
{
|
|
int w;
|
|
char *hold, *temp, *temp_msg;
|
|
|
|
hold = message;
|
|
|
|
while(1) {
|
|
temp = strchr(hold, ',');
|
|
if (temp != NULL) {
|
|
temp_msg = malloc(temp-hold+1);
|
|
strncpy(temp_msg, hold, (temp-hold));
|
|
temp_msg[(temp-hold)] = '\0';
|
|
hold = temp+1;
|
|
} else temp_msg = hold;
|
|
|
|
write(Fvwm_fd[0], &window, sizeof(unsigned long));
|
|
|
|
w=strlen(temp_msg);
|
|
write(Fvwm_fd[0], &w, sizeof(int));
|
|
write(Fvwm_fd[0], temp_msg, w);
|
|
|
|
/* keep going */
|
|
w = 1;
|
|
write(Fvwm_fd[0], &w, sizeof(int));
|
|
|
|
if(temp_msg != hold)
|
|
free(temp_msg);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Detected a broken pipe - time to exit
|
|
Based on DeadPipe() from FvwmIdent:
|
|
Copyright 1994, Robert Nation and Nobutaka Suzuki.
|
|
**********************************************************************/
|
|
void DeadPipe(int nonsense)
|
|
{
|
|
ConsoleMessage("received SIGPIPE signal: exiting...\n");
|
|
ShutMeDown(1);
|
|
}
|
|
|
|
/******************************************************************************
|
|
WaitForExpose - Used to wait for expose event so we don't draw too early
|
|
******************************************************************************/
|
|
void WaitForExpose(void)
|
|
{
|
|
XEvent Event;
|
|
|
|
while(1) {
|
|
XNextEvent(dpy, &Event);
|
|
if (Event.type == Expose) {
|
|
if (Event.xexpose.count == 0) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
RedrawWindow - Update the needed lines and erase any old ones
|
|
******************************************************************************/
|
|
void RedrawWindow(int force)
|
|
{
|
|
if (Tip.open) RedrawTipWindow();
|
|
if (force) {
|
|
XClearArea (dpy, win, 0, 0, win_width, win_height, False);
|
|
DrawGoodies();
|
|
}
|
|
DrawButtonArray(&buttons, force);
|
|
StartButtonDraw(force);
|
|
if (XQLength(dpy) && !force) LoopOnEvents();
|
|
}
|
|
|
|
/******************************************************************************
|
|
ConsoleMessage - Print a message on the console. Works like printf.
|
|
******************************************************************************/
|
|
void ConsoleMessage(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);
|
|
fflush(console);
|
|
#endif
|
|
}
|
|
|
|
/******************************************************************************
|
|
OpenConsole - Open the console as a way of sending messages
|
|
******************************************************************************/
|
|
int OpenConsole()
|
|
{
|
|
#ifndef NO_CONSOLE
|
|
if ((console = fopen("/dev/console","w")) == NULL) {
|
|
fprintf(stderr, "%s: cannot open console\n", Module);
|
|
return 0;
|
|
}
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
void ParseConfig() {
|
|
char *buf;
|
|
while (GetConfigLine(Fvwm_fd,&buf), buf != NULL) {
|
|
ParseConfigLine(buf);
|
|
} /* end config lines */
|
|
} /* end function */
|
|
|
|
static void ParseConfigLine(char *tline) {
|
|
char *str;
|
|
int i, j;
|
|
|
|
while (isspace(*tline))tline++;
|
|
if(strncasecmp(tline, CatString3(Module, "Font",""),Clength+4)==0)
|
|
CopyString(&font_string,&tline[Clength+4]);
|
|
else if(strncasecmp(tline, CatString3(Module, "SelFont",""),Clength+7)==0)
|
|
CopyString(&selfont_string,&tline[Clength+7]);
|
|
else if(strncasecmp(tline,CatString3(Module,"Fore",""), Clength+4)==0) {
|
|
CopyString(&ForeColor,&tline[Clength+4]);
|
|
} else if(strncasecmp(tline,CatString3(Module, "Geometry",""), Clength+8)==0) {
|
|
str = &tline[Clength+9];
|
|
while(((isspace(*str))&&(*str != '\n'))&&(*str != 0)) str++;
|
|
str[strlen(str)-1] = 0;
|
|
UpdateString(&geometry,str);
|
|
} else if(strncasecmp(tline,CatString3(Module, "Back",""), Clength+4)==0)
|
|
CopyString(&BackColor,&tline[Clength+4]);
|
|
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, "AutoStick",""),
|
|
Clength+9)==0) AutoStick=True;
|
|
else if(strncasecmp(tline,CatString3(Module, "AutoHide",""),
|
|
Clength+4)==0) { AutoHide=True; AutoStick=True; }
|
|
else if(strncasecmp(tline,CatString3(Module, "UseIconNames",""),
|
|
Clength+12)==0) UseIconNames=True;
|
|
else if(strncasecmp(tline,CatString3(Module, "ShowTransients",""),
|
|
Clength+14)==0) ShowTransients=True;
|
|
else if(strncasecmp(tline,CatString3(Module, "UpdateInterval",""),
|
|
Clength+14)==0)
|
|
UpdateInterval=atoi(&tline[Clength+14]);
|
|
else if(strncasecmp(tline,CatString3(Module, "HighlightFocus",""),
|
|
Clength+14)==0) HighlightFocus=True;
|
|
else if(strncasecmp(tline,CatString3(Module, "SwallowModule",""),
|
|
Clength+13)==0) {
|
|
|
|
/* tell fvwm to launch the module for us */
|
|
str = safemalloc(strlen(&tline[Clength+13]) + 6);
|
|
sprintf(str, "Module %s",&tline[Clength+13]);
|
|
ConsoleMessage("Trying to: %s", str);
|
|
SendFvwmPipe(str, 0);
|
|
|
|
/* Remember the anticipated window's name for swallowing */
|
|
i = 4;
|
|
while((str[i] != 0)&&
|
|
(str[i] != '"'))
|
|
i++;
|
|
j = ++i;
|
|
while((str[i] != 0)&&
|
|
(str[i] != '"'))
|
|
i++;
|
|
if (i > j) {
|
|
str[i] = 0;
|
|
ConsoleMessage("Looking for window: [%s]\n", &str[j]);
|
|
AddItemName(&swallowed, &str[j], F_NOT_SWALLOWED);
|
|
}
|
|
free(str);
|
|
} else if(strncasecmp(tline,CatString3(Module, "Swallow",""),
|
|
Clength+7)==0) {
|
|
|
|
/* tell fvwm to Exec the process for us */
|
|
str = safemalloc(strlen(&tline[Clength+7]) + 6);
|
|
sprintf(str, "Exec %s",&tline[Clength+7]);
|
|
ConsoleMessage("Trying to: %s", str);
|
|
SendFvwmPipe(str, 0);
|
|
|
|
/* Remember the anticipated window's name for swallowing */
|
|
i = 4;
|
|
while((str[i] != 0)&&
|
|
(str[i] != '"'))
|
|
i++;
|
|
j = ++i;
|
|
while((str[i] != 0)&&
|
|
(str[i] != '"'))
|
|
i++;
|
|
if (i > j) {
|
|
str[i] = 0;
|
|
ConsoleMessage("Looking for window: [%s]\n", &str[j]);
|
|
AddItemName(&swallowed, &str[j], F_NOT_SWALLOWED);
|
|
}
|
|
free(str);
|
|
} else if(strncasecmp(tline,"ButtonWidth",11) == 0) {
|
|
button_width = atoi(&tline[11]);
|
|
} else if(strncasecmp(tline,"IconPath",8) == 0) {
|
|
CopyString(&IconPath, &tline[8]);
|
|
} else if(strncasecmp(tline,"PixmapPath",10) == 0) {
|
|
CopyString(&PixmapPath, &tline[10]);
|
|
} else {
|
|
GoodiesParseConfig(tline, Module);
|
|
StartButtonParseConfig(tline, Module);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
Swallow a process window
|
|
******************************************************************************/
|
|
void Swallow(unsigned long *body) {
|
|
XSizeHints hints;
|
|
long supplied;
|
|
int h,w;
|
|
|
|
/* Swallow the window */
|
|
XUnmapWindow(dpy, body[0]);
|
|
|
|
if (!XGetWMNormalHints (dpy, (Window)body[0], &hints, &supplied))
|
|
hints.flags = 0;
|
|
h = win_height - 10; w = 80;
|
|
ConstrainSize(&hints, &w, &h);
|
|
XResizeWindow(dpy,(Window)body[0], w, h);
|
|
|
|
stwin_width += w + 2;
|
|
|
|
XReparentWindow(dpy,(Window)body[0], win,
|
|
win_width - stwin_width + goodies_width + 2, 5);
|
|
goodies_width += w + 2;
|
|
|
|
XMapWindow(dpy,body[0]);
|
|
XSelectInput(dpy,(Window)body[0],
|
|
PropertyChangeMask|StructureNotifyMask);
|
|
|
|
|
|
/* Do not swallow it next time */
|
|
UpdateNameItem(&swallowed, (char*)&body[3], body[0], F_SWALLOWED);
|
|
ConsoleMessage("-> Swallowed: %s\n",(char*)&body[3]);
|
|
RedrawWindow(1);
|
|
}
|
|
|
|
/******************************************************************************
|
|
Alarm - Handle a SIGALRM - used to implement timeout events
|
|
******************************************************************************/
|
|
void Alarm(int nonsense) {
|
|
|
|
switch(AlarmSet) {
|
|
|
|
case SHOW_TIP:
|
|
ShowTipWindow(1);
|
|
break;
|
|
|
|
case HIDE_TASK_BAR:
|
|
HideTaskBar();
|
|
break;
|
|
}
|
|
|
|
AlarmSet = NOT_SET;
|
|
signal (SIGALRM, Alarm);
|
|
}
|
|
|
|
/******************************************************************************
|
|
CheckForTip - determine when to popup the tip window
|
|
******************************************************************************/
|
|
void CheckForTip(int x, int y) {
|
|
int num, bx, by, trunc;
|
|
char *name;
|
|
|
|
if (MouseInStartButton(x, y)) {
|
|
if (Tip.type != START_TIP) PopupTipWindow(3, 0, "Click here to start");
|
|
Tip.type = START_TIP;
|
|
}
|
|
else if (MouseInMail(x, y)) {
|
|
if (Tip.type != MAIL_TIP) CreateMailTipWindow();
|
|
Tip.type = MAIL_TIP;
|
|
}
|
|
else if (MouseInClock(x, y)) {
|
|
if (Tip.type != DATE_TIP) CreateDateWindow();
|
|
Tip.type = DATE_TIP;
|
|
}
|
|
else {
|
|
num = LocateButton(&buttons, x, y, &bx, &by, &name, &trunc);
|
|
if (num != -1 && trunc) {
|
|
if ((Tip.type != num) ||
|
|
(Tip.text == NULL) || (strcmp(name, Tip.text) != 0))
|
|
PopupTipWindow(bx+3, by, name);
|
|
Tip.type = num;
|
|
} else {
|
|
Tip.type = NO_TIP;
|
|
}
|
|
}
|
|
|
|
if (Tip.type != NO_TIP) {
|
|
if (!AlarmSet && !Tip.open) {
|
|
alarm(1);
|
|
AlarmSet = 1;
|
|
}
|
|
if (AlarmSet != SHOW_TIP && !Tip.open)
|
|
SetAlarm(SHOW_TIP);
|
|
} else {
|
|
if (AlarmSet) {
|
|
alarm(0);
|
|
AlarmSet = 0;
|
|
}
|
|
ClearAlarm();
|
|
if (Tip.open) ShowTipWindow(0);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
LoopOnEvents - Process all the X events we get
|
|
******************************************************************************/
|
|
void LoopOnEvents()
|
|
{
|
|
int num = 0;
|
|
char tmp[100];
|
|
XEvent Event;
|
|
int x, y, redraw;
|
|
static unsigned long lasttime = 0L;
|
|
|
|
while(XPending(dpy)) {
|
|
redraw = -1;
|
|
XNextEvent(dpy, &Event);
|
|
|
|
switch(Event.type) {
|
|
case ButtonRelease:
|
|
num = WhichButton(&buttons, Event.xbutton.x, Event.xbutton.y);
|
|
if (num != -1) {
|
|
ButReleased = ButPressed; /* Avoid race fvwm pipe */
|
|
BelayHide = True; /* Don't AutoHide when function ends */
|
|
SendFvwmPipe(ClickAction[Event.xbutton.button-1],
|
|
ItemID(&windows, num));
|
|
redraw = 0;
|
|
}
|
|
|
|
if (HighlightFocus) {
|
|
if (num == ButPressed) RadioButton(&buttons, num, BUTTON_DOWN);
|
|
if (num != -1) SendFvwmPipe("Focus 0", ItemID(&windows, num));
|
|
}
|
|
ButPressed = -1;
|
|
break;
|
|
|
|
case ButtonPress:
|
|
RadioButton(&buttons, -1, BUTTON_UP); /* no windows focused anymore */
|
|
if (MouseInStartButton(Event.xbutton.x, Event.xbutton.y)) {
|
|
StartButtonUpdate(NULL, BUTTON_DOWN);
|
|
x = win_x;
|
|
if (win_y < Midline) {
|
|
/* bar in top half of the screen */
|
|
y = win_y + RowHeight;
|
|
} else {
|
|
/* bar in bottom of the screen */
|
|
y = win_y - ScreenHeight;
|
|
}
|
|
sprintf(tmp,"Popup %s %d %d", StartPopup, x, y);
|
|
SendFvwmPipe(tmp, ItemID(&windows, num));
|
|
} else if (MouseInMail(Event.xbutton.x, Event.xbutton.y)) {
|
|
HandleMailClick(Event);
|
|
} else {
|
|
num = WhichButton(&buttons, Event.xbutton.x, Event.xbutton.y);
|
|
UpdateButton(&buttons, num, NULL, (ButPressed == num) ?
|
|
BUTTON_BRIGHT : BUTTON_DOWN);
|
|
|
|
/* UpdateButton(&buttons, num, NULL, BUTTON_DOWN);*/
|
|
ButPressed = num;
|
|
}
|
|
/* else { / * Move taskbar * /
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
SendFvwmPipe("Move", win);
|
|
|
|
}
|
|
*/
|
|
redraw = 0;
|
|
break;
|
|
|
|
case Expose:
|
|
if (Event.xexpose.count == 0)
|
|
if (Event.xexpose.window == Tip.win)
|
|
redraw = 0;
|
|
else
|
|
redraw = 1;
|
|
break;
|
|
|
|
case ClientMessage:
|
|
if ((Event.xclient.format==32) && (Event.xclient.data.l[0]==wm_del_win))
|
|
ShutMeDown(0);
|
|
break;
|
|
|
|
case EnterNotify:
|
|
if (AutoHide) RevealTaskBar();
|
|
|
|
if (Event.xcrossing.mode != NotifyNormal) break;
|
|
num = WhichButton(&buttons, Event.xcrossing.x, Event.xcrossing.y);
|
|
if (!HighlightFocus) {
|
|
if (SomeButtonDown(Event.xcrossing.state)) {
|
|
if (num != -1) {
|
|
RadioButton(&buttons, num, BUTTON_DOWN);
|
|
ButPressed = num;
|
|
redraw = 0;
|
|
} else {
|
|
ButPressed = -1;
|
|
}
|
|
}
|
|
} else {
|
|
if (num != -1 && num != ButPressed)
|
|
SendFvwmPipe("Focus 0", ItemID(&windows, num));
|
|
}
|
|
|
|
CheckForTip(Event.xmotion.x, Event.xmotion.y);
|
|
break;
|
|
|
|
case LeaveNotify:
|
|
ClearAlarm();
|
|
if (Tip.open) ShowTipWindow(0);
|
|
|
|
if (Event.xcrossing.mode != NotifyNormal) break;
|
|
|
|
if (AutoHide) SetAlarm(HIDE_TASK_BAR);
|
|
|
|
if (!HighlightFocus) {
|
|
if (SomeButtonDown(Event.xcrossing.state)) {
|
|
if (ButPressed != -1) {
|
|
RadioButton(&buttons, -1, BUTTON_UP);
|
|
ButPressed = -1;
|
|
redraw = 0;
|
|
}
|
|
} else {
|
|
if (ButReleased != -1) {
|
|
RadioButton(&buttons, -1, BUTTON_UP);
|
|
ButReleased = -1;
|
|
redraw = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MotionNotify:
|
|
num = WhichButton(&buttons, Event.xmotion.x, Event.xmotion.y);
|
|
if (!HighlightFocus) {
|
|
if (SomeButtonDown(Event.xmotion.state) && num != ButPressed) {
|
|
if (num != -1) {
|
|
RadioButton(&buttons, num, BUTTON_DOWN);
|
|
ButPressed = num;
|
|
} else {
|
|
RadioButton(&buttons, num, BUTTON_UP);
|
|
ButPressed = -1;
|
|
}
|
|
redraw = 0;
|
|
}
|
|
} else {
|
|
if (num != -1 && num != ButPressed)
|
|
SendFvwmPipe("Focus 0", ItemID(&windows, num));
|
|
}
|
|
|
|
CheckForTip(Event.xmotion.x, Event.xmotion.y);
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
if ((Event.xconfigure.width != win_width ||
|
|
Event.xconfigure.height != win_height)) {
|
|
AdjustWindow(Event.xconfigure.width, Event.xconfigure.height);
|
|
if (AutoStick) WarpTaskBar(win_y);
|
|
redraw = 1;
|
|
}
|
|
else if (Event.xconfigure.x != win_x || Event.xconfigure.y != win_y) {
|
|
if (AutoStick) {
|
|
WarpTaskBar(Event.xconfigure.y);
|
|
} else {
|
|
win_x = Event.xconfigure.x;
|
|
win_y = Event.xconfigure.y;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (redraw >= 0) RedrawWindow(redraw);
|
|
|
|
if (Event.xkey.time - lasttime > UpdateInterval*1000L) {
|
|
DrawGoodies();
|
|
lasttime = Event.xkey.time;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/***********************************
|
|
AdjustWindow - Resize the window
|
|
**********************************/
|
|
void AdjustWindow(int width, int height)
|
|
{
|
|
NRows = (height+2)/RowHeight;
|
|
win_height = height;
|
|
win_width = width;
|
|
ArrangeButtonArray(&buttons);
|
|
}
|
|
|
|
/******************************************************************************
|
|
makename - Based on the flags return me '(name)' or 'name'
|
|
******************************************************************************/
|
|
char *makename(char *string,long flags)
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=safemalloc(strlen(string)+3);
|
|
if (flags&ICONIFIED) strcpy(ptr,"(");
|
|
else strcpy(ptr,"");
|
|
strcat(ptr,string);
|
|
if (flags&ICONIFIED) strcat(ptr,")");
|
|
return ptr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
LinkAction - Link an response to a users action
|
|
******************************************************************************/
|
|
void LinkAction(char *string)
|
|
{
|
|
char *temp;
|
|
temp=string;
|
|
while(isspace(*temp)) temp++;
|
|
if(strncasecmp(temp, "Click1", 6)==0)
|
|
CopyString(&ClickAction[0],&temp[6]);
|
|
else if(strncasecmp(temp, "Click2", 6)==0)
|
|
CopyString(&ClickAction[1],&temp[6]);
|
|
else if(strncasecmp(temp, "Click3", 6)==0)
|
|
CopyString(&ClickAction[2],&temp[6]);
|
|
else if(strncasecmp(temp, "Enter", 5)==0)
|
|
CopyString(&EnterAction,&temp[5]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
StartMeUp - Do X initialization things
|
|
******************************************************************************/
|
|
void StartMeUp()
|
|
{
|
|
XSizeHints hints;
|
|
XGCValues gcval;
|
|
unsigned long gcmask;
|
|
int ret;
|
|
|
|
if (!(dpy = XOpenDisplay(""))) {
|
|
fprintf(stderr,"%s: can't open display %s", Module,
|
|
XDisplayName(""));
|
|
exit (1);
|
|
}
|
|
x_fd = XConnectionNumber(dpy);
|
|
screen= DefaultScreen(dpy);
|
|
Root = RootWindow(dpy, screen);
|
|
d_depth = DefaultDepth(dpy, screen);
|
|
|
|
ScreenWidth = XDisplayWidth(dpy, screen);
|
|
ScreenHeight = XDisplayHeight(dpy, screen);
|
|
|
|
Midline = (int) (ScreenHeight >> 1);
|
|
|
|
if (selfont_string == NULL) selfont_string = font_string;
|
|
|
|
if ((ButtonFont = XLoadQueryFont(dpy, font_string)) == NULL) {
|
|
if ((ButtonFont = XLoadQueryFont(dpy, "fixed")) == NULL) {
|
|
ConsoleMessage("Couldn't load fixed font. Exiting!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
if ((SelButtonFont = XLoadQueryFont(dpy, selfont_string)) == NULL) {
|
|
if ((SelButtonFont = XLoadQueryFont(dpy, "fixed")) == NULL) {
|
|
ConsoleMessage("Couldn't load fixed font. Exiting!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
fontheight = SelButtonFont->ascent + SelButtonFont->descent;
|
|
|
|
NRows = 1;
|
|
RowHeight = fontheight + 8;
|
|
|
|
win_border = 4; /* default border width */
|
|
win_height = RowHeight;
|
|
win_width = ScreenWidth - (win_border << 1);
|
|
|
|
ret = XParseGeometry(geometry, &hints.x, &hints.y,
|
|
(unsigned int *)&hints.width,
|
|
(unsigned int *)&hints.height);
|
|
|
|
if (ret & YNegative)
|
|
hints.y = ScreenHeight - (AutoHide ? 1 : win_height + (win_border<<1));
|
|
else
|
|
hints.y = AutoHide ? 1 - win_height : 0;
|
|
|
|
hints.flags=USPosition|PPosition|USSize|PSize|PResizeInc|
|
|
PWinGravity|PMinSize|PMaxSize|PBaseSize;
|
|
hints.x = 0;
|
|
hints.width = win_width;
|
|
hints.height = RowHeight;
|
|
hints.width_inc = win_width;
|
|
hints.height_inc = RowHeight+2;
|
|
hints.win_gravity = NorthWestGravity;
|
|
hints.min_width = win_width;
|
|
hints.min_height = RowHeight;
|
|
hints.min_height = win_height;
|
|
hints.max_width = win_width;
|
|
hints.max_height = RowHeight+7*(RowHeight+2) + 1;
|
|
hints.base_width = win_width;
|
|
hints.base_height = RowHeight;
|
|
|
|
win_x = hints.x;
|
|
win_y = hints.y;
|
|
|
|
if(d_depth < 2) {
|
|
back = GetColor("white");
|
|
fore = GetColor("black");
|
|
} else {
|
|
back = GetColor(BackColor);
|
|
fore = GetColor(ForeColor);
|
|
}
|
|
|
|
win=XCreateSimpleWindow(dpy,Root,hints.x,hints.y,
|
|
hints.width,hints.height,0,
|
|
fore,back);
|
|
|
|
wm_del_win=XInternAtom(dpy,"WM_DELETE_WINDOW",False);
|
|
XSetWMProtocols(dpy,win,&wm_del_win,1);
|
|
|
|
XSetWMNormalHints(dpy,win,&hints);
|
|
|
|
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_MAXIMIZE|MWM_DECOR_MINIMIZE,
|
|
MWM_FUNC_ALL|MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE,
|
|
MWM_INPUT_MODELESS);
|
|
*/
|
|
gcmask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
|
|
gcval.foreground = fore;
|
|
gcval.background = back;
|
|
gcval.font = SelButtonFont->fid;
|
|
gcval.graphics_exposures = False;
|
|
graph = XCreateGC(dpy,Root,gcmask,&gcval);
|
|
|
|
if(d_depth < 2)
|
|
gcval.foreground = GetShadow(fore);
|
|
else
|
|
gcval.foreground = GetShadow(back);
|
|
gcval.background = back;
|
|
gcmask = GCForeground | GCBackground | GCGraphicsExposures;
|
|
shadow = XCreateGC(dpy,Root,gcmask,&gcval);
|
|
|
|
gcval.foreground = GetHilite(back);
|
|
gcval.background = back;
|
|
hilite = XCreateGC(dpy,Root,gcmask,&gcval);
|
|
|
|
gcval.foreground = GetColor("white");;
|
|
gcval.background = back;
|
|
whitegc = XCreateGC(dpy,Root,gcmask,&gcval);
|
|
|
|
gcval.foreground = GetColor("black");
|
|
gcval.background = back;
|
|
blackgc = XCreateGC(dpy,Root,gcmask,&gcval);
|
|
|
|
gcmask = GCForeground | GCBackground | GCTile |
|
|
GCFillStyle | GCGraphicsExposures;
|
|
gcval.foreground = GetHilite(back);
|
|
gcval.background = back;
|
|
gcval.fill_style = FillTiled;
|
|
gcval.tile = XCreatePixmapFromBitmapData(dpy, Root, (char *)gray_bits,
|
|
gray_width, gray_height,
|
|
gcval.foreground, gcval.background, d_depth);
|
|
checkered = XCreateGC(dpy, Root, gcmask, &gcval);
|
|
|
|
XSelectInput(dpy,win,(ExposureMask | KeyPressMask | PointerMotionMask |
|
|
EnterWindowMask | LeaveWindowMask |
|
|
StructureNotifyMask));
|
|
/* ResizeRedirectMask | */
|
|
ChangeWindowName(&Module[1]);
|
|
|
|
InitGoodies();
|
|
|
|
}
|
|
|
|
/******************************************************************************
|
|
ShutMeDown - Do X client cleanup
|
|
******************************************************************************/
|
|
void ShutMeDown(int exitstat)
|
|
{
|
|
FreeList(&windows);
|
|
FreeAllButtons(&buttons);
|
|
XFreeGC(dpy,graph);
|
|
XDestroyWindow(dpy, win);
|
|
XCloseDisplay(dpy);
|
|
exit(exitstat);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
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);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* ConstrainSize - adjust the given width and height to account for the
|
|
* constraints imposed by size hints
|
|
*
|
|
* The general algorithm, especially the aspect ratio stuff, is
|
|
* borrowed from uwm's CheckConsistency routine.
|
|
*
|
|
***********************************************************************/
|
|
void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp)
|
|
{
|
|
#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
|
|
#define _min(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
|
int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
|
|
int baseWidth, baseHeight;
|
|
int dwidth = *widthp, dheight = *heightp;
|
|
|
|
if(hints->flags & PMinSize)
|
|
{
|
|
minWidth = hints->min_width;
|
|
minHeight = hints->min_height;
|
|
if(hints->flags & PBaseSize)
|
|
{
|
|
baseWidth = hints->base_width;
|
|
baseHeight = hints->base_height;
|
|
}
|
|
else
|
|
{
|
|
baseWidth = hints->min_width;
|
|
baseHeight = hints->min_height;
|
|
}
|
|
}
|
|
else if(hints->flags & PBaseSize)
|
|
{
|
|
minWidth = hints->base_width;
|
|
minHeight = hints->base_height;
|
|
baseWidth = hints->base_width;
|
|
baseHeight = hints->base_height;
|
|
}
|
|
else
|
|
{
|
|
minWidth = 1;
|
|
minHeight = 1;
|
|
baseWidth = 1;
|
|
baseHeight = 1;
|
|
}
|
|
|
|
if(hints->flags & PMaxSize)
|
|
{
|
|
maxWidth = hints->max_width;
|
|
maxHeight = hints->max_height;
|
|
}
|
|
else
|
|
{
|
|
maxWidth = 10000;
|
|
maxHeight = 10000;
|
|
}
|
|
if(hints->flags & PResizeInc)
|
|
{
|
|
xinc = hints->width_inc;
|
|
yinc = hints->height_inc;
|
|
}
|
|
else
|
|
{
|
|
xinc = 1;
|
|
yinc = 1;
|
|
}
|
|
|
|
/*
|
|
* First, clamp to min and max values
|
|
*/
|
|
if (dwidth < minWidth) dwidth = minWidth;
|
|
if (dheight < minHeight) dheight = minHeight;
|
|
|
|
if (dwidth > maxWidth) dwidth = maxWidth;
|
|
if (dheight > maxHeight) dheight = maxHeight;
|
|
|
|
|
|
/*
|
|
* Second, fit to base + N * inc
|
|
*/
|
|
dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
|
|
dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
|
|
|
|
|
|
/*
|
|
* Third, adjust for aspect ratio
|
|
*/
|
|
#define maxAspectX hints->max_aspect.x
|
|
#define maxAspectY hints->max_aspect.y
|
|
#define minAspectX hints->min_aspect.x
|
|
#define minAspectY hints->min_aspect.y
|
|
/*
|
|
* The math looks like this:
|
|
*
|
|
* minAspectX dwidth maxAspectX
|
|
* ---------- <= ------- <= ----------
|
|
* minAspectY dheight maxAspectY
|
|
*
|
|
* If that is multiplied out, then the width and height are
|
|
* invalid in the following situations:
|
|
*
|
|
* minAspectX * dheight > minAspectY * dwidth
|
|
* maxAspectX * dheight < maxAspectY * dwidth
|
|
*
|
|
*/
|
|
|
|
if (hints->flags & PAspect)
|
|
{
|
|
if (minAspectX * dheight > minAspectY * dwidth)
|
|
{
|
|
delta = makemult(minAspectX * dheight / minAspectY - dwidth,
|
|
xinc);
|
|
if (dwidth + delta <= maxWidth)
|
|
dwidth += delta;
|
|
else
|
|
{
|
|
delta = makemult(dheight - dwidth*minAspectY/minAspectX,
|
|
yinc);
|
|
if (dheight - delta >= minHeight) dheight -= delta;
|
|
}
|
|
}
|
|
|
|
if (maxAspectX * dheight < maxAspectY * dwidth)
|
|
{
|
|
delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
|
|
yinc);
|
|
if (dheight + delta <= maxHeight)
|
|
dheight += delta;
|
|
else
|
|
{
|
|
delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
|
|
xinc);
|
|
if (dwidth - delta >= minWidth) dwidth -= delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
*widthp = dwidth;
|
|
*heightp = dheight;
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************
|
|
WarpTaskBar -- Enforce AutoStick feature
|
|
***********************************************************************/
|
|
void WarpTaskBar(int y) {
|
|
win_x = win_border;
|
|
|
|
if (y < Midline)
|
|
win_y = win_border;
|
|
else
|
|
win_y = (int)ScreenHeight - win_height - win_border;
|
|
|
|
XMoveWindow(dpy, win, win_x, win_y);
|
|
if (AutoHide) SetAlarm(HIDE_TASK_BAR);
|
|
|
|
/* Prevent oscillations caused by race with
|
|
time delayed TaskBarHide(). Is there any way
|
|
to prevent these Xevents from being sent
|
|
to the server in the first place? */
|
|
PurgeConfigEvents();
|
|
}
|
|
|
|
/***********************************************************************
|
|
RevealTaskBar -- Make taskbar fully visible
|
|
***********************************************************************/
|
|
void RevealTaskBar() {
|
|
ClearAlarm();
|
|
|
|
if (win_y < Midline)
|
|
win_y = win_border;
|
|
else
|
|
win_y = (int)ScreenHeight - win_height - win_border;
|
|
|
|
BelayHide = False;
|
|
XMoveWindow(dpy, win, win_x, win_y);
|
|
}
|
|
|
|
/***********************************************************************
|
|
HideTaskbar -- Make taskbar partially visible
|
|
***********************************************************************/
|
|
void HideTaskBar() {
|
|
ClearAlarm();
|
|
|
|
if (win_y < Midline)
|
|
win_y = 2 - win_height;
|
|
else
|
|
win_y = (int)ScreenHeight - 2;
|
|
|
|
XMoveWindow(dpy, win, win_x, win_y);
|
|
}
|
|
|
|
/***********************************************************************
|
|
SetAlarm -- Schedule a timeout event
|
|
************************************************************************/
|
|
void SetAlarm(int event) {
|
|
AlarmSet = event;
|
|
alarm(1);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ClearAlarm -- Disable timeout events
|
|
************************************************************************/
|
|
void ClearAlarm(void) {
|
|
if(AlarmSet) {
|
|
AlarmSet = NOT_SET;
|
|
alarm(0);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
PurgeConfigEvents -- Wait for and purge ConfigureNotify events.
|
|
************************************************************************/
|
|
void PurgeConfigEvents(void) {
|
|
XEvent Event;
|
|
|
|
XPeekEvent(dpy, &Event);
|
|
while (XCheckTypedWindowEvent(dpy, win, ConfigureNotify, &Event));
|
|
}
|
|
|
|
/************************************************************************
|
|
X Error Handler
|
|
************************************************************************/
|
|
XErrorHandler ErrorHandler(Display *d, XErrorEvent *event)
|
|
{
|
|
char errmsg[256];
|
|
|
|
XGetErrorText(d, event->error_code, errmsg, 256);
|
|
ConsoleMessage("%s failed request: %s\n", Module, errmsg);
|
|
ConsoleMessage("Major opcode: 0x%x, resource id: 0x%x\n",
|
|
event->request_code, event->resourceid);
|
|
return NULL;
|
|
}
|