734adbdbbca607e1ebc3811289ebf3cd29d84a36
[oweals/cde.git] / cde / lib / tt / lib / tttk / tttk.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $TOG: tttk.C /main/5 1999/09/14 13:00:44 mgreess $                                                        
28 #if defined(linux)
29 # include <sys/poll.h>
30 #else
31 # include <poll.h>
32 #endif
33 #include <errno.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include "api/c/tt_c.h"
37 #include "util/tt_gettext.h"
38 #include "util/tt_Xlib.h"
39 #include "util/tt_port.h"
40 #include "tttk/tttk.h"
41 #include "tttk/tttk2free.h"
42 #include "tttk/tttkutils.h"
43 #include "tttk/tttkpattern.h"
44 #include "tttk/ttdtprocid.h"
45 #include "tttk/ttdesktop.h"
46
47 extern Tt_status        _tt_errno_status( int err_no );
48
49 const char  *Tttk_integer               = "integer";
50 const char  *Tttk_string                = "string";
51 const char  *Tttk_boolean               = "boolean";
52 const char  *Tttk_file                  = "File";
53 const char  *Tttk_message_id            = "messageID";
54 const char  *Tttk_title                 = "title";
55 const char  *Tttk_width                 = "width";
56 const char  *Tttk_height                = "height";
57 const char  *Tttk_xoffset               = "xOffset";
58 const char  *Tttk_yoffset               = "yOffset";
59
60 _TtDtProcid *_ttdtme                    = 0;
61
62 // API calls below...
63
64 char *
65 ttdt_open(
66         int            *ttFD,
67         const char     *toolName,
68         const char     *vendor,
69         const char     *version,
70         int             sendStarted
71 )
72 {
73         _ttdtme = new _TtDtProcid( toolName, vendor, version );
74         if (_ttdtme == 0) {
75                 return (char *)tt_error_pointer( TT_ERR_NOMEM );
76         }
77         char *procID = tt_open();
78         Tt_status status = tt_ptr_error( procID );
79         if (status != TT_OK) {
80                 return procID;
81         }
82         *ttFD = tt_fd();
83         status = tt_int_error( *ttFD );
84         if (status != TT_OK) {
85                 tt_free( procID );
86                 tt_close();
87                 return (char *)tt_error_pointer( status );
88         }
89         if (sendStarted) {
90                 ttdt_Started( 0, toolName, vendor, version, 1 );
91         }
92         return procID;
93 }
94
95 //
96 // A callback used internally to pick geometry info out of
97 // a Get_Geometry reply and stuff it into (DisplayInfo *)clientData.
98 //
99 static Tt_message
100 _ttDtApplyGeom(
101         Tt_message      msg,
102         void           *clientData,
103         Tt_message      ,
104         int             width,
105         int             height,
106         int             xOffset,
107         int             yOffset
108 )
109 {
110         DisplayInfo *info = (DisplayInfo *)clientData;
111         if (info != 0) {
112                 info->repliesOutStanding--;
113                 info->width = width;
114                 info->height = height;
115                 info->xOffset = xOffset;
116                 info->yOffset = yOffset;
117         }
118         tttk_message_destroy( msg );
119         return 0;
120 }
121
122 //
123 // A TtDtGetXInfoMsgCB used internally to pick X11 info out of
124 // a Get_XInfo reply and stuff it into (DisplayInfo *)clientData.
125 //
126 static Tt_message
127 _ttDtApplyXInfo(
128         Tt_message      msg,
129         void           *clientData,
130         Tt_message      ,
131         char           *display,
132         int,            //visual
133         int             //depth
134 )
135 {
136         DisplayInfo *info = (DisplayInfo *)clientData;
137         if (info != 0) {
138                 info->repliesOutStanding--;
139                 info->display = display;
140         }
141         tttk_message_destroy( msg );
142         return 0;
143 }
144
145 Tt_status
146 ttdt_sender_imprint_on(
147         const char     *handler,
148         Tt_message      commission,
149         char          **pDisplay,
150         int            *width,
151         int            *height,
152         int            *xOffset,
153         int            *yOffset,
154         XtAppContext    app2run,
155         int             msTimeOut
156 )
157 {
158         Tt_status status;
159         Tt_message msg;
160         DisplayInfo info;
161         info.repliesOutStanding = 0;
162         info.width = -1;
163         info.height = -1;
164         info.xOffset = INT_MAX;
165         info.yOffset = INT_MAX;
166         info.display = 0;
167         if ((width != 0) || (height != 0) || (xOffset != 0) || (yOffset != 0)){
168                 msg = ttdt_Get_Geometry( handler, commission,
169                                          _ttDtApplyGeom, &info, 1 );
170                 status = tt_ptr_error( msg );
171                 if (status == TT_OK) {
172                         info.repliesOutStanding++;
173                 }
174         }
175         // XXX sending XInfo before Geometry causes segv in handler!? Saberize.
176         msg = ttdt_Get_XInfo( handler, commission,
177                               _ttDtApplyXInfo, &info, 1);
178         status = tt_ptr_error( msg );
179         if (status == TT_OK) {
180                 info.repliesOutStanding++;
181         }
182         msg = ttdt_Get_Locale( handler, commission, 0, &info, 0, 1 );
183         status = tt_ptr_error( msg );
184         if (status == TT_OK) {
185                 info.repliesOutStanding++;
186         }
187         msg = ttdt_Get_Situation( handler, commission, 0, &info, 1 );
188         status = tt_ptr_error( msg );
189         if (status == TT_OK) {
190                 info.repliesOutStanding++;
191         }
192         if (info.repliesOutStanding == 0) {
193                 return status;
194         }
195         status = tttk_block_while( app2run,
196                                    &info.repliesOutStanding, msTimeOut );
197         if (pDisplay == 0) {
198                 if (info.display != 0) {
199                         _tt_putenv( "DISPLAY", info.display );
200                 }
201                 tt_free( info.display );
202         } else {
203                 *pDisplay = info.display;
204         }
205         if (width != 0) {
206                 *width = info.width;
207         }
208         if (height != 0) {
209                 *height = info.height;
210         }
211         if (xOffset != 0) {
212                 *xOffset = info.xOffset;
213         }
214         if (yOffset != 0) {
215                 *yOffset = info.yOffset;
216         }
217         return status;
218 }
219
220 Tt_status
221 ttdt_close(
222         const char     *procid,
223         const char     *newProcid,
224         int             sendStopped
225 )
226 {
227         Tt_status status;
228         if (procid != 0) {
229                 status = tt_default_procid_set( procid );
230                 if (status != TT_OK) {
231                         return status;
232                 }
233         }
234         if (sendStopped) {
235                 ttdt_Stopped( 0, _ttdtme->toolname(), _ttdtme->vendor(),
236                               _ttdtme->version(), 1 );
237         }
238         status = tt_close();
239         if (status != TT_OK) {
240                 return status;
241         }
242         if (newProcid != 0) {
243                 status = tt_default_procid_set( newProcid );
244                 if (status != TT_OK) {
245                         return status;
246                 }
247         }
248         return TT_OK;
249 }
250
251 Tt_pattern *
252 ttdt_session_join(
253         const char             *sessid,
254         Ttdt_contract_cb        cb,
255         Widget                  shell,
256         void                   *clientdata,
257         int                     join
258 )
259 {
260         Tt_status       status;
261         _TttkItem2Free  item2free;
262         if (sessid == 0) {
263                 sessid = tt_default_session();
264                 status = tt_ptr_error( sessid );
265                 if (status != TT_OK) {
266                         return (Tt_pattern *)tt_error_pointer( status );
267                 }
268                 item2free = (char *)sessid;
269         }
270         Tt_pattern *pats = _ttdtme->pats_create( 0, cb, shell, clientdata );
271         if (join) {
272                 status = tt_session_join( sessid );
273                 if (status != TT_OK) {
274                         return (Tt_pattern *)tt_error_pointer( status );
275                 }
276         }
277         return pats;
278 }
279
280 Tt_status
281 ttdt_session_quit(
282         const char     *sessid,
283         Tt_pattern     *pats,
284         int             quit
285 )
286 {
287         Tt_status       status;
288         _TttkItem2Free  item2free;
289         if (sessid == 0) {
290                 sessid = tt_default_session();
291                 status = tt_ptr_error( sessid );
292                 if (status != TT_OK) {
293                         return status;
294                 }
295                 item2free = (char *)sessid;
296         }
297         status = _tttk_patterns_destroy( pats );
298         if (status != TT_OK) {
299                 return status;
300         }
301         if (quit) {
302                 status = tt_session_quit( sessid );
303                 if (status != TT_OK) {
304                         return status;
305                 }
306         }
307         return status;
308 }
309
310 Tt_pattern *
311 ttdt_message_accept(
312         Tt_message      contract,
313         Ttdt_contract_cb cb,
314         Widget          shell,
315         void           *clientData,
316         int             accept,
317         int             sendStatus
318 )
319 {
320         Tt_status status;
321         if (accept) {
322                 status = tt_message_accept( contract );
323                 if (status != TT_OK) {
324                         // Not fatal
325                 }
326         }
327         Tt_pattern *pats = _ttdtme->pats_create( contract, cb, shell,
328                                                  clientData );
329         status = tt_ptr_error( pats );
330         if (status == TT_OK) {
331                 tt_message_user_set( contract, _TttkContractKey, pats );
332         }
333         if (sendStatus) {
334                 ttdt_Status( contract, contract,
335                              catgets( _ttcatd, 1, 24, "Accepting request" ),
336                              _ttdtme->toolname(), _ttdtme->vendor(),
337                              _ttdtme->version(), 1 );
338         }
339         return pats;
340 }
341
342 Tt_pattern *
343 ttdt_subcontract_manage(
344         Tt_message              subcontract,
345         Ttdt_contract_cb        cb,
346         Widget                  shell,
347         void                   *clientData
348 )
349 {
350         const int numPats = 4;
351         Tt_pattern *pats = (Tt_pattern *)malloc(numPats * sizeof(Tt_pattern));
352         if (pats == 0) {
353                 return (Tt_pattern *)tt_error_pointer( TT_ERR_NOMEM );
354         }
355         pats[ 0 ] = 0;
356         if (shell != 0) {
357                 pats[0] = ttdt_Get_Geometry_pat( TT_HANDLE, subcontract,
358                                 _ttdt_do_GSet_Geometry, shell, 1 );
359                 pats[1] = ttdt_Get_XInfo_pat( TT_HANDLE, subcontract,
360                                 _ttdt_do_Get_XInfo, shell, 1 );
361         } else {
362                 pats[0] = ttdt_Get_Geometry_pat( TT_HANDLE, subcontract,
363                                 (Ttdt_Geometry_out_cb)cb, clientData, 1 );
364                 pats[1] = ttdt_Get_XInfo_pat(   TT_HANDLE, subcontract,
365                                 (Ttdt_XInfo_out_cb)cb, clientData, 1 );
366         }
367         pats[2] = _ttdt_pat(    TTDT_STATUS, _ttdt_contract_cb, TT_OBSERVE,
368                                 subcontract, cb, clientData, 1 );
369         pats[ numPats - 1 ] = 0;
370         for (int i = 0; i < numPats; i++) {
371                 Tt_status status = tt_ptr_error( pats[ i ] );
372                 if (status != TT_OK) {
373                         _tttk_patterns_destroy( pats );
374                         free( pats );
375                         return (Tt_pattern *)tt_error_pointer( status );
376                 }
377         }
378         tt_message_user_set( subcontract, _TttkSubContractKey, pats );
379         return pats;
380 }
381
382 void
383 tttk_Xt_input_handler(
384         XtPointer  procid,
385         int       *,
386         XtInputId *id
387 )
388 {
389         static const char *here = "ttdt_Xt_input_handler()";
390
391         Tt_message msg = _tttk_message_receive( (char *)procid );
392         Tt_status status = tt_ptr_error( msg );
393         if (status != TT_OK) {
394                 _ttDtPrintStatus( here, "tttk_message_receive()", status);
395                 if (status == TT_ERR_NOMP) {
396                         ttdt_close( (const char *)procid, 0, 0 );
397                         if (! _tt_load_xt()) {
398                                 return;
399                         }
400                         if (id != 0) {
401                                 CALLXT(XtRemoveInput)( *id );
402                         }
403                 }
404                 return;
405         }
406         if (msg == 0) {
407                 return;
408         }
409         status = tttk_message_abandon( msg );
410         if (status != TT_OK) {
411                 _ttDtPrintStatus( here, "tttk_message_abandon()", status );
412         }
413 }
414
415 Tt_status
416 _tttk_block_procid_while(
417         const int     *blocked,
418         int            msTimeOut
419 )
420 {
421         int fd = tt_fd();
422         Tt_status status = tt_int_error( fd );
423         if (status != TT_OK) {
424                 return status;
425         }
426         while ((blocked == 0) || (*blocked > 0)) {
427                 struct pollfd fds[ 1 ];
428                 fds[0].fd = fd;
429                 fds[0].events = POLLIN;
430                 int activeFDs = poll( fds, 1, msTimeOut );
431                 if (activeFDs == 0) {
432                         return TT_DESKTOP_ETIMEDOUT;
433                 } else if (activeFDs < 0) {
434               if ((blocked != 0) && (*blocked)) {
435                                 _ttDtPError( "_tttk_block_procid_while()",
436                                              "poll()" );
437                                 return _tt_errno_status( errno );
438                         }
439                 }
440                 if (fds[ 0 ].revents != 0) {
441                         //
442                         // AIX has fd in struct pollfd as a long, not
443                         // an int, and complains (justifiably) when
444                         // long* is passed when int* is needed. So use
445                         // call-by-value-return instead of
446                         // call-by-reference.  Hey,
447                         // tttk_Xt_input_handler doesn\'t use the
448                         // value anyway...
449                         //
450                         int fd_temp;
451                         fd_temp = fds[0].fd;
452                         tttk_Xt_input_handler( 0, &fd_temp, 0 );
453                         fds[0].fd = fd_temp;
454                 }
455                 if (msTimeOut == 0) {
456                         return TT_OK;
457                 }
458          if (msTimeOut == 0) {
459             return TT_OK;
460          }
461      }
462         return TT_OK;
463 }
464
465 void
466 _tttk_timed_out(
467         XtPointer       p_timed_out,
468         XtIntervalId
469 )
470 {
471         *(int *)p_timed_out = 1;
472 }
473
474 Tt_status
475 _tttk_block_app_while(
476         XtAppContext    app2run,
477         const int     *blocked,
478         int            msTimeOut
479 )
480 {
481         XtIntervalId alarm = 0;
482      if ((blocked != 0) && (*blocked <= 0)) return TT_OK;
483         int timed_out = (msTimeOut == 0);
484         if ((! _tt_load_xt()) || (! _tt_load_xlib())) {
485                 return TT_ERR_ACCESS; // i.e. ELIBACC
486         }
487         if ((timed_out) && (! CALLXT(XtAppPending)( app2run ))) {
488                 //
489                 // We are non-blocking and no input is available,
490                 // so return.
491                 //
492                 return TT_DESKTOP_ETIMEDOUT;
493         }
494         if (msTimeOut > 0) {
495                 alarm = CALLXT(XtAppAddTimeOut)( app2run,
496                                         (unsigned long)msTimeOut,
497                                         (XtTimerCallbackProc)_tttk_timed_out,
498                                         &timed_out );
499         }
500         do {
501                 CALLXT(XtAppProcessEvent)( app2run, XtIMAll );
502         } while ((! timed_out) && ((blocked == 0) || (*blocked > 0)));
503         if (alarm != 0) {
504                 CALLXT(XtRemoveTimeOut)( alarm );
505         }
506         if (timed_out && (msTimeOut > 0)) {
507                 return TT_DESKTOP_ETIMEDOUT;
508         }
509         return TT_OK;
510 }
511
512 Tt_status
513 tttk_block_while(
514         XtAppContext    app2run,
515         const int     *blocked,
516         int            msTimeOut
517 )
518 {
519         if (app2run == 0) {
520                 return _tttk_block_procid_while( blocked, msTimeOut );
521         } else {
522                 return _tttk_block_app_while( app2run, blocked, msTimeOut );
523         }
524 }