525 lines
12 KiB
C
525 lines
12 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
|
|
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
|
|
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
|
|
//%% (c) Copyright 1993, 1994 Novell, Inc.
|
|
//%% $TOG: tttk.C /main/5 1999/09/14 13:00:44 mgreess $
|
|
#if defined(linux)
|
|
# include <sys/poll.h>
|
|
#else
|
|
# include <poll.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include "api/c/tt_c.h"
|
|
#include "util/tt_gettext.h"
|
|
#include "util/tt_Xlib.h"
|
|
#include "util/tt_port.h"
|
|
#include "tttk/tttk.h"
|
|
#include "tttk/tttk2free.h"
|
|
#include "tttk/tttkutils.h"
|
|
#include "tttk/tttkpattern.h"
|
|
#include "tttk/ttdtprocid.h"
|
|
#include "tttk/ttdesktop.h"
|
|
|
|
extern Tt_status _tt_errno_status( int err_no );
|
|
|
|
const char *Tttk_integer = "integer";
|
|
const char *Tttk_string = "string";
|
|
const char *Tttk_boolean = "boolean";
|
|
const char *Tttk_file = "File";
|
|
const char *Tttk_message_id = "messageID";
|
|
const char *Tttk_title = "title";
|
|
const char *Tttk_width = "width";
|
|
const char *Tttk_height = "height";
|
|
const char *Tttk_xoffset = "xOffset";
|
|
const char *Tttk_yoffset = "yOffset";
|
|
|
|
_TtDtProcid *_ttdtme = 0;
|
|
|
|
// API calls below...
|
|
|
|
char *
|
|
ttdt_open(
|
|
int *ttFD,
|
|
const char *toolName,
|
|
const char *vendor,
|
|
const char *version,
|
|
int sendStarted
|
|
)
|
|
{
|
|
_ttdtme = new _TtDtProcid( toolName, vendor, version );
|
|
if (_ttdtme == 0) {
|
|
return (char *)tt_error_pointer( TT_ERR_NOMEM );
|
|
}
|
|
char *procID = tt_open();
|
|
Tt_status status = tt_ptr_error( procID );
|
|
if (status != TT_OK) {
|
|
return procID;
|
|
}
|
|
*ttFD = tt_fd();
|
|
status = tt_int_error( *ttFD );
|
|
if (status != TT_OK) {
|
|
tt_free( procID );
|
|
tt_close();
|
|
return (char *)tt_error_pointer( status );
|
|
}
|
|
if (sendStarted) {
|
|
ttdt_Started( 0, toolName, vendor, version, 1 );
|
|
}
|
|
return procID;
|
|
}
|
|
|
|
//
|
|
// A callback used internally to pick geometry info out of
|
|
// a Get_Geometry reply and stuff it into (DisplayInfo *)clientData.
|
|
//
|
|
static Tt_message
|
|
_ttDtApplyGeom(
|
|
Tt_message msg,
|
|
void *clientData,
|
|
Tt_message ,
|
|
int width,
|
|
int height,
|
|
int xOffset,
|
|
int yOffset
|
|
)
|
|
{
|
|
DisplayInfo *info = (DisplayInfo *)clientData;
|
|
if (info != 0) {
|
|
info->repliesOutStanding--;
|
|
info->width = width;
|
|
info->height = height;
|
|
info->xOffset = xOffset;
|
|
info->yOffset = yOffset;
|
|
}
|
|
tttk_message_destroy( msg );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// A TtDtGetXInfoMsgCB used internally to pick X11 info out of
|
|
// a Get_XInfo reply and stuff it into (DisplayInfo *)clientData.
|
|
//
|
|
static Tt_message
|
|
_ttDtApplyXInfo(
|
|
Tt_message msg,
|
|
void *clientData,
|
|
Tt_message ,
|
|
char *display,
|
|
int, //visual
|
|
int //depth
|
|
)
|
|
{
|
|
DisplayInfo *info = (DisplayInfo *)clientData;
|
|
if (info != 0) {
|
|
info->repliesOutStanding--;
|
|
info->display = display;
|
|
}
|
|
tttk_message_destroy( msg );
|
|
return 0;
|
|
}
|
|
|
|
Tt_status
|
|
ttdt_sender_imprint_on(
|
|
const char *handler,
|
|
Tt_message commission,
|
|
char **pDisplay,
|
|
int *width,
|
|
int *height,
|
|
int *xOffset,
|
|
int *yOffset,
|
|
XtAppContext app2run,
|
|
int msTimeOut
|
|
)
|
|
{
|
|
Tt_status status;
|
|
Tt_message msg;
|
|
DisplayInfo info;
|
|
info.repliesOutStanding = 0;
|
|
info.width = -1;
|
|
info.height = -1;
|
|
info.xOffset = INT_MAX;
|
|
info.yOffset = INT_MAX;
|
|
info.display = 0;
|
|
if ((width != 0) || (height != 0) || (xOffset != 0) || (yOffset != 0)){
|
|
msg = ttdt_Get_Geometry( handler, commission,
|
|
_ttDtApplyGeom, &info, 1 );
|
|
status = tt_ptr_error( msg );
|
|
if (status == TT_OK) {
|
|
info.repliesOutStanding++;
|
|
}
|
|
}
|
|
// XXX sending XInfo before Geometry causes segv in handler!? Saberize.
|
|
msg = ttdt_Get_XInfo( handler, commission,
|
|
_ttDtApplyXInfo, &info, 1);
|
|
status = tt_ptr_error( msg );
|
|
if (status == TT_OK) {
|
|
info.repliesOutStanding++;
|
|
}
|
|
msg = ttdt_Get_Locale( handler, commission, 0, &info, 0, 1 );
|
|
status = tt_ptr_error( msg );
|
|
if (status == TT_OK) {
|
|
info.repliesOutStanding++;
|
|
}
|
|
msg = ttdt_Get_Situation( handler, commission, 0, &info, 1 );
|
|
status = tt_ptr_error( msg );
|
|
if (status == TT_OK) {
|
|
info.repliesOutStanding++;
|
|
}
|
|
if (info.repliesOutStanding == 0) {
|
|
return status;
|
|
}
|
|
status = tttk_block_while( app2run,
|
|
&info.repliesOutStanding, msTimeOut );
|
|
if (pDisplay == 0) {
|
|
if (info.display != 0) {
|
|
_tt_putenv( "DISPLAY", info.display );
|
|
}
|
|
tt_free( info.display );
|
|
} else {
|
|
*pDisplay = info.display;
|
|
}
|
|
if (width != 0) {
|
|
*width = info.width;
|
|
}
|
|
if (height != 0) {
|
|
*height = info.height;
|
|
}
|
|
if (xOffset != 0) {
|
|
*xOffset = info.xOffset;
|
|
}
|
|
if (yOffset != 0) {
|
|
*yOffset = info.yOffset;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Tt_status
|
|
ttdt_close(
|
|
const char *procid,
|
|
const char *newProcid,
|
|
int sendStopped
|
|
)
|
|
{
|
|
Tt_status status;
|
|
if (procid != 0) {
|
|
status = tt_default_procid_set( procid );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
if (sendStopped) {
|
|
ttdt_Stopped( 0, _ttdtme->toolname(), _ttdtme->vendor(),
|
|
_ttdtme->version(), 1 );
|
|
}
|
|
status = tt_close();
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
if (newProcid != 0) {
|
|
status = tt_default_procid_set( newProcid );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
return TT_OK;
|
|
}
|
|
|
|
Tt_pattern *
|
|
ttdt_session_join(
|
|
const char *sessid,
|
|
Ttdt_contract_cb cb,
|
|
Widget shell,
|
|
void *clientdata,
|
|
int join
|
|
)
|
|
{
|
|
Tt_status status;
|
|
_TttkItem2Free item2free;
|
|
if (sessid == 0) {
|
|
sessid = tt_default_session();
|
|
status = tt_ptr_error( sessid );
|
|
if (status != TT_OK) {
|
|
return (Tt_pattern *)tt_error_pointer( status );
|
|
}
|
|
item2free = (char *)sessid;
|
|
}
|
|
Tt_pattern *pats = _ttdtme->pats_create( 0, cb, shell, clientdata );
|
|
if (join) {
|
|
status = tt_session_join( sessid );
|
|
if (status != TT_OK) {
|
|
return (Tt_pattern *)tt_error_pointer( status );
|
|
}
|
|
}
|
|
return pats;
|
|
}
|
|
|
|
Tt_status
|
|
ttdt_session_quit(
|
|
const char *sessid,
|
|
Tt_pattern *pats,
|
|
int quit
|
|
)
|
|
{
|
|
Tt_status status;
|
|
_TttkItem2Free item2free;
|
|
if (sessid == 0) {
|
|
sessid = tt_default_session();
|
|
status = tt_ptr_error( sessid );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
item2free = (char *)sessid;
|
|
}
|
|
status = _tttk_patterns_destroy( pats );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
if (quit) {
|
|
status = tt_session_quit( sessid );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Tt_pattern *
|
|
ttdt_message_accept(
|
|
Tt_message contract,
|
|
Ttdt_contract_cb cb,
|
|
Widget shell,
|
|
void *clientData,
|
|
int accept,
|
|
int sendStatus
|
|
)
|
|
{
|
|
Tt_status status;
|
|
if (accept) {
|
|
status = tt_message_accept( contract );
|
|
if (status != TT_OK) {
|
|
// Not fatal
|
|
}
|
|
}
|
|
Tt_pattern *pats = _ttdtme->pats_create( contract, cb, shell,
|
|
clientData );
|
|
status = tt_ptr_error( pats );
|
|
if (status == TT_OK) {
|
|
tt_message_user_set( contract, _TttkContractKey, pats );
|
|
}
|
|
if (sendStatus) {
|
|
ttdt_Status( contract, contract,
|
|
catgets( _ttcatd, 1, 24, "Accepting request" ),
|
|
_ttdtme->toolname(), _ttdtme->vendor(),
|
|
_ttdtme->version(), 1 );
|
|
}
|
|
return pats;
|
|
}
|
|
|
|
Tt_pattern *
|
|
ttdt_subcontract_manage(
|
|
Tt_message subcontract,
|
|
Ttdt_contract_cb cb,
|
|
Widget shell,
|
|
void *clientData
|
|
)
|
|
{
|
|
const int numPats = 4;
|
|
Tt_pattern *pats = (Tt_pattern *)malloc(numPats * sizeof(Tt_pattern));
|
|
if (pats == 0) {
|
|
return (Tt_pattern *)tt_error_pointer( TT_ERR_NOMEM );
|
|
}
|
|
pats[ 0 ] = 0;
|
|
if (shell != 0) {
|
|
pats[0] = ttdt_Get_Geometry_pat( TT_HANDLE, subcontract,
|
|
_ttdt_do_GSet_Geometry, shell, 1 );
|
|
pats[1] = ttdt_Get_XInfo_pat( TT_HANDLE, subcontract,
|
|
_ttdt_do_Get_XInfo, shell, 1 );
|
|
} else {
|
|
pats[0] = ttdt_Get_Geometry_pat( TT_HANDLE, subcontract,
|
|
(Ttdt_Geometry_out_cb)cb, clientData, 1 );
|
|
pats[1] = ttdt_Get_XInfo_pat( TT_HANDLE, subcontract,
|
|
(Ttdt_XInfo_out_cb)cb, clientData, 1 );
|
|
}
|
|
pats[2] = _ttdt_pat( TTDT_STATUS, _ttdt_contract_cb, TT_OBSERVE,
|
|
subcontract, (void *)cb, clientData, 1 );
|
|
pats[ numPats - 1 ] = 0;
|
|
for (int i = 0; i < numPats; i++) {
|
|
Tt_status status = tt_ptr_error( pats[ i ] );
|
|
if (status != TT_OK) {
|
|
_tttk_patterns_destroy( pats );
|
|
free( pats );
|
|
return (Tt_pattern *)tt_error_pointer( status );
|
|
}
|
|
}
|
|
tt_message_user_set( subcontract, _TttkSubContractKey, pats );
|
|
return pats;
|
|
}
|
|
|
|
void
|
|
tttk_Xt_input_handler(
|
|
XtPointer procid,
|
|
int *,
|
|
XtInputId *id
|
|
)
|
|
{
|
|
static const char *here = "ttdt_Xt_input_handler()";
|
|
|
|
Tt_message msg = _tttk_message_receive( (char *)procid );
|
|
Tt_status status = tt_ptr_error( msg );
|
|
if (status != TT_OK) {
|
|
_ttDtPrintStatus( here, "tttk_message_receive()", status);
|
|
if (status == TT_ERR_NOMP) {
|
|
ttdt_close( (const char *)procid, 0, 0 );
|
|
if (! _tt_load_xt()) {
|
|
return;
|
|
}
|
|
if (id != 0) {
|
|
CALLXT(XtRemoveInput)( *id );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (msg == 0) {
|
|
return;
|
|
}
|
|
status = tttk_message_abandon( msg );
|
|
if (status != TT_OK) {
|
|
_ttDtPrintStatus( here, "tttk_message_abandon()", status );
|
|
}
|
|
}
|
|
|
|
Tt_status
|
|
_tttk_block_procid_while(
|
|
const int *blocked,
|
|
int msTimeOut
|
|
)
|
|
{
|
|
int fd = tt_fd();
|
|
Tt_status status = tt_int_error( fd );
|
|
if (status != TT_OK) {
|
|
return status;
|
|
}
|
|
while ((blocked == 0) || (*blocked > 0)) {
|
|
struct pollfd fds[ 1 ];
|
|
fds[0].fd = fd;
|
|
fds[0].events = POLLIN;
|
|
int activeFDs = poll( fds, 1, msTimeOut );
|
|
if (activeFDs == 0) {
|
|
return TT_DESKTOP_ETIMEDOUT;
|
|
} else if (activeFDs < 0) {
|
|
if ((blocked != 0) && (*blocked)) {
|
|
_ttDtPError( "_tttk_block_procid_while()",
|
|
"poll()" );
|
|
return _tt_errno_status( errno );
|
|
}
|
|
}
|
|
if (fds[ 0 ].revents != 0) {
|
|
//
|
|
// AIX has fd in struct pollfd as a long, not
|
|
// an int, and complains (justifiably) when
|
|
// long* is passed when int* is needed. So use
|
|
// call-by-value-return instead of
|
|
// call-by-reference. Hey,
|
|
// tttk_Xt_input_handler doesn\'t use the
|
|
// value anyway...
|
|
//
|
|
int fd_temp;
|
|
fd_temp = fds[0].fd;
|
|
tttk_Xt_input_handler( 0, &fd_temp, 0 );
|
|
fds[0].fd = fd_temp;
|
|
}
|
|
if (msTimeOut == 0) {
|
|
return TT_OK;
|
|
}
|
|
if (msTimeOut == 0) {
|
|
return TT_OK;
|
|
}
|
|
}
|
|
return TT_OK;
|
|
}
|
|
|
|
void
|
|
_tttk_timed_out(
|
|
XtPointer p_timed_out,
|
|
XtIntervalId
|
|
)
|
|
{
|
|
*(int *)p_timed_out = 1;
|
|
}
|
|
|
|
Tt_status
|
|
_tttk_block_app_while(
|
|
XtAppContext app2run,
|
|
const int *blocked,
|
|
int msTimeOut
|
|
)
|
|
{
|
|
XtIntervalId alarm = 0;
|
|
if ((blocked != 0) && (*blocked <= 0)) return TT_OK;
|
|
int timed_out = (msTimeOut == 0);
|
|
if ((! _tt_load_xt()) || (! _tt_load_xlib())) {
|
|
return TT_ERR_ACCESS; // i.e. ELIBACC
|
|
}
|
|
if ((timed_out) && (! CALLXT(XtAppPending)( app2run ))) {
|
|
//
|
|
// We are non-blocking and no input is available,
|
|
// so return.
|
|
//
|
|
return TT_DESKTOP_ETIMEDOUT;
|
|
}
|
|
if (msTimeOut > 0) {
|
|
alarm = CALLXT(XtAppAddTimeOut)( app2run,
|
|
(unsigned long)msTimeOut,
|
|
(XtTimerCallbackProc)_tttk_timed_out,
|
|
&timed_out );
|
|
}
|
|
do {
|
|
CALLXT(XtAppProcessEvent)( app2run, XtIMAll );
|
|
} while ((! timed_out) && ((blocked == 0) || (*blocked > 0)));
|
|
if (alarm != 0) {
|
|
CALLXT(XtRemoveTimeOut)( alarm );
|
|
}
|
|
if (timed_out && (msTimeOut > 0)) {
|
|
return TT_DESKTOP_ETIMEDOUT;
|
|
}
|
|
return TT_OK;
|
|
}
|
|
|
|
Tt_status
|
|
tttk_block_while(
|
|
XtAppContext app2run,
|
|
const int *blocked,
|
|
int msTimeOut
|
|
)
|
|
{
|
|
if (app2run == 0) {
|
|
return _tttk_block_procid_while( blocked, msTimeOut );
|
|
} else {
|
|
return _tttk_block_app_while( app2run, blocked, msTimeOut );
|
|
}
|
|
}
|