/*
* session.cc
*
* Copyright (C) 1995-2001 Kenichi Kourai
*
* 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, 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 qvwm; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef USE_XSMP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/SM/SMlib.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
#include "main.h"
#include "session.h"
#include "desktop.h"
#include "qvwm.h"
#include "list.h"
void
Session::DieCallback(SmcConn arg_connId, SmPointer client_data)
{
((Session*)client_data)->Die(arg_connId);
}
void
Session::SaveCompleteCallback(SmcConn arg_connId, SmPointer client_data)
{
((Session*)client_data)->SaveComplete(arg_connId);
}
void
Session::ShutdownCancelledCallback(SmcConn arg_connId, SmPointer client_data)
{
((Session*)client_data)->ShutdownCancelled(arg_connId);
}
void
Session::SaveYourselfPhase2Callback(SmcConn arg_connId, SmPointer client_data)
{
((Session*)client_data)->SaveYourselfPhase2(arg_connId);
}
void
Session::SaveYourselfCallback(SmcConn arg_connId,
SmPointer client_data,
int save_type,
Bool shutdown,
int interact_style,
Bool fast)
{
((Session*)client_data)->SaveYourself(arg_connId,
save_type, shutdown,
interact_style, fast);
}
void
Session::IceConnWatchCallback(IceConn conn,
IcePointer client_data,
Bool opening,
IcePointer* watch_data)
{
((Session*)client_data)->IceConnWatch(conn, opening, watch_data);
}
void
Session::Die(SmcConn arg_connId)
{
desktop.FinishQvwm(False);
}
void
Session::SaveComplete(SmcConn arg_connId)
{
}
void
Session::ShutdownCancelled(SmcConn arg_connId)
{
if (!saveDone) {
SmcSaveYourselfDone(connId, False);
saveDone = True;
}
}
void
Session::SaveYourselfPhase2(SmcConn arg_connId)
{
FILE* fp = OpenSessionFile("w");
if (!fp) {
if (!saveDone) {
SmcSaveYourselfDone(connId, False);
saveDone = True;
}
return;
}
List<Qvwm>* qvwmList = &desktop.GetQvwmList();
List<Qvwm>::Iterator i(qvwmList);
Qvwm* qvWm;
int idx=0;
for (qvWm = i.GetHead(); qvWm; qvWm = i.GetNext()) {
if (!qvWm->SavePropertiesToFile(idx++, fp)) {
//break;
}
}
fclose(fp);
if (!saveDone) {
SmcSaveYourselfDone(connId, qvWm ? False : True);
saveDone = True;
}
}
void
Session::SaveYourself(SmcConn arg_connId,
int save_type, Bool shutdown,
int interact_style, Bool fast)
{
if (!SmcRequestSaveYourselfPhase2(connId,
&SaveYourselfPhase2Callback,
(SmPointer)this)) {
SmcSaveYourselfDone(connId, False);
saveDone = True;
} else {
saveDone = False;
}
}
void
Session::IceConnWatch(IceConn conn,
Bool opening,
IcePointer* watch_data)
{
if (opening) {
if (iceConnFd < 0) {
iceConnFd = IceConnectionNumber(conn);
}
} else if (IceConnectionNumber(conn) == iceConnFd) {
iceConnFd = -1;
}
}
void
Session::InitializeProperties()
{
// SmClone
int argv0_len = strlen(qvArgv[0]);
SmPropValue cloneCommandValue[1] = {
{argv0_len,qvArgv[0]}
};
SmProp cloneCommand = {
SmCloneCommand,
SmLISTofARRAY8,
1,
cloneCommandValue
};
// SmDiscardCommand
int path_rm_len = strlen(PATH_RM);
int session_file_len = strlen(sessionFile);
SmPropValue discardCommandValue[3] = {
{path_rm_len, (void *)PATH_RM},
{3, (void *)"-f"},
{session_file_len, sessionFile}
};
SmProp discardCommand = {
SmDiscardCommand,
SmLISTofARRAY8,
3,
discardCommandValue
};
// SmProgram
SmPropValue programValue[1] = {
{argv0_len,qvArgv[0]}
};
SmProp program = {
SmProgram,
SmARRAY8,
1,
programValue
};
// SmRestartCommand
char* client_id_arg = "-clientId";
int client_id_len = strlen(clientId);
SmPropValue restartCommandValue[3] = {
{argv0_len, qvArgv[0]},
{9, client_id_arg},
{client_id_len, clientId}
};
SmProp restartCommand = {
SmRestartCommand,
SmLISTofARRAY8,
3,
restartCommandValue
};
// UserID
char* user_id = getenv("USER");
int user_id_len = strlen(user_id);
SmPropValue userIdValue[1] = {
{user_id_len, user_id}
};
SmProp userId = {
SmUserID,
SmARRAY8,
1,
userIdValue
};
char val = 30;
SmPropValue gsmPriorityValue[1] = {
{1, &val}
};
SmProp gsmPriority = {
"_GSM_Priority",
SmCARD8,
1,
gsmPriorityValue
};
SmProp *properties[6] = {
&cloneCommand,
&discardCommand,
&program,
&restartCommand,
&userId,
&gsmPriority
};
SmcSetProperties(connId, 6, properties);
}
Bool
Session::ConnectSessionManager(char* arg_previousId)
{
SmcCallbacks callbacks;
char errorStringRet[256];
callbacks.save_yourself.callback = &SaveYourselfCallback;
callbacks.save_yourself.client_data = (SmPointer)this;
callbacks.die.callback = &DieCallback;
callbacks.die.client_data = (SmPointer)this;
callbacks.save_complete.callback = &SaveCompleteCallback;
callbacks.save_complete.client_data = (SmPointer)this;;
callbacks.shutdown_cancelled.callback = &ShutdownCancelledCallback;
callbacks.shutdown_cancelled.client_data = (SmPointer)this;;
connId = SmcOpenConnection(NULL, NULL, 1, 0,
// the 1.0 spec requires support of all procs
SmcSaveYourselfProcMask |
SmcDieProcMask |
SmcSaveCompleteProcMask |
SmcShutdownCancelledProcMask,
&callbacks,
arg_previousId,
&clientId,
sizeof(errorStringRet),
errorStringRet);
return (connId == NULL) ? False : True;
}
Session::Session(char* arg_previousId)
{
status = False;
iceConnFd = -1;
saveDone = False;
sessionFile[0] = '\0';
connId = NULL;
if (!getenv("SESSION_MANAGER"))
return;
if (!IceAddConnectionWatch(&IceConnWatchCallback, (IcePointer)this))
return;
if (!ConnectSessionManager(arg_previousId))
return;
iceConn = SmcGetIceConnection(connId);
if (!getenv("HOME") ||
strlen(getenv("HOME")) + strlen(clientId) + 12 > sizeof sessionFile)
return;
sprintf(sessionFile, "%s/.qvwm/%s.ini", getenv("HOME"), clientId);
InitializeProperties();
status = True;
}
Session::~Session()
{
if (status)
SmcCloseConnection(connId, 0, NULL);
}
#if 0
void
Session::debug(char* fmt_string, ...)
{
va_list ap;
va_start(ap, fmt_string);
FILE* fp = fopen("/tmp/qvwm-error", "a");
if (fp == NULL)
return;
vfprintf(fp, fmt_string, ap);
fclose(fp);
va_end(ap);
}
#endif
void
Session::CloseConnection()
{
SmcCloseConnection(connId, 0, NULL);
iceConn = NULL;
iceConnFd = -1;
}
Bool
Session::RequestQuit()
{
if (!status)
return False;
SmcRequestSaveYourself(connId,
SmSaveBoth,
True, // shutdown is taking place
SmInteractStyleAny,
False, // not fast
True); // global
return True;
}
FILE*
Session::OpenSessionFile(const char* mode)
{
char* dir;
dir = new char[strlen(getenv("HOME")) + 7];
if (dir == NULL) {
return NULL;
}
sprintf(dir, "%s/.qvwm", getenv("HOME"));
struct stat st;
if (stat(dir, &st) != 0) {
if (errno != ENOENT) { // ENOENT == 'dir' does not exist.
return NULL;
}
mkdir(dir, 0755);
}
delete [] dir;
return fopen(sessionFile, mode);
}
Bool
Session::ReadVector(char** p, int* x, int* y)
{
*x = 0;
*y = 0;
while (**p && isdigit(**p))
*x = *x * 10 + (*(*p)++ - '0');
if (*(*p)++ != ',')
return False;
while (**p && isdigit(**p))
*y = *y * 10 + (*(*p)++ - '0');
return True;
}
Bool
Session::LoadSessionFile()
{
if (!status)
return False;
FILE* fp = OpenSessionFile("r");
if (!fp) {
return True;
}
char buf[1024];
size_t l;
int idx = -1;
int cur_idx;
char *p, *key;
int x, y;
QvwmProto* qp = NULL;
while (feof(fp) == 0) {
if (fgets(buf, sizeof buf, fp) == NULL)
break;
l = strlen(buf);
if (buf[l - 1] == '\n') // chomp!
buf[--l] = '\0';
p = buf;
if (!isdigit(*p))
continue;
cur_idx = 0;
while (isdigit(*p))
cur_idx = cur_idx * 10 + (*p++ - '0');
if (cur_idx != idx) {
// new hint.
if (qp) {
qvwmProtoList.InsertTail(qp);
qp = NULL;
}
idx = cur_idx;
qp = new QvwmProto();
}
if (*p != ',')
continue;
key = ++p;
while (*p && *p != '=')
p++;
if (!*p)
continue;
*p++ = '\0';
if (strcmp(key, "id") == 0) {
qp->SetId(p);
} else if (strcmp(key, "class") == 0) {
qp->SetRClass(p);
} else if (strcmp(key, "rname") == 0) {
qp->SetRName(p);
} else if (strcmp(key, "name") == 0) {
qp->SetName(p);
} else if (strcmp(key, "pos") == 0) {
if (ReadVector(&p, &x, &y))
qp->SetPos(x, y);
} else if (strcmp(key, "size") == 0) {
if (ReadVector(&p, &x, &y))
qp->SetSize(x, y);
#if 0
} else if (strcmp(key, "flags") == 0) {
unsigned long f = 0;
// read something..
qp->SetFlags(f);
#endif
} else {
// do nothing
}
}
if (qp) {
qvwmProtoList.InsertTail(qp);
}
fclose(fp);
return True;
}
#if 0
void
QvwmProto::dump(const char* label)
{
Session::debug(" QP: %s: (%s,%s,%s,%s,%s,x=%d,y=%d,w=%d,h=%d)\n",
label, id, role, res_class, res_name, name,
x, y,
width, height);
}
#endif
Bool
Session::SearchProto(const unsigned char* smid,
const unsigned char* wm_role,
const char* rclass, const char* rname,
const char* name,
int* x, int* y, int* width, int* height /*,int* flags*/)
{
if (!status)
return False;
List<QvwmProto>* qlist = &qvwmProtoList;
List<QvwmProto>::Iterator i(qlist);
QvwmProto* qp;
Bool found = False;
for (qp = i.GetHead(); qp; qp = i.GetNext()) {
const char* qsmid = qp->GetId();
const char* qrole = qp->GetRole();
if ((!smid && qsmid) ||
(smid && !qsmid) ||
(smid && qsmid && strcmp((const char*)smid, (const char*)qsmid))) {
continue;
}
if (wm_role || qrole) {
if (wm_role && qrole &&
strcmp((const char*)wm_role, (const char*)qrole) == 0) {
found = True;
break;
}
}
const char* qrclass = qp->GetRClass();
const char* qrname = qp->GetRName();
const char* qname = qp->GetName();
if (!rclass || !rname || !qrclass || !qrname) {
continue;
}
// compare WM_CLASS and WM_NAME to identify the window
if (strcmp(rclass, qrclass) == 0 && strcmp(rname, qrname) == 0 &&
strcmp(name, qname) == 0) {
if (qsmid) {
found = True;
break;
}
// SM_CLIENT_ID is not set. Check other attributes to indetify.
// (but not implemented)
}
}
if (found) {
*x = qp->GetX();
*y = qp->GetY();
*width = qp->GetWidth();
*height = qp->GetHeight();
//*flags = qp->GetFlags();
qvwmProtoList.Remove(qp);
return True;
}
return False;
}
// end of session.cc
#endif // USE_XSMP
syntax highlighted by Code2HTML, v. 0.9.1