2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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: ttdesktop.C /main/4 1999/10/14 19:06:10 mgreess $
29 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
31 #include "tt_options.h"
35 #include <sys/utsname.h>
38 #include <sys/resource.h>
42 #if defined(OPT_SYSINFO)
43 #include <sys/systeminfo.h>
45 #include <netdb.h> // MAXHOSTNAMELEN
46 #include <sys/param.h> // MAXHOSTNAMELEN on AIX
47 // Because otherwise e.g. XtNiconic cashes out as XtShellStrings[nnn]
48 #define XTSTRINGDEFINES
49 #include <X11/Intrinsic.h>
50 #include <X11/StringDefs.h>
51 #include <X11/Shell.h>
52 #include "api/c/tt_c.h"
53 #include "api/c/api_api.h"
54 #include "util/tt_Xlib.h"
55 #include "util/tt_port.h"
56 #include "tttk/tttk.h"
57 #include "tttk/tttk2free.h"
58 #include "tttk/tttkutils.h"
59 #include "tttk/tttkmessage.h"
60 #include "tttk/tttkpattern.h"
61 #include "tttk/ttdtprocid.h"
62 #include "tttk/ttdesktop.h"
64 extern _TtDtProcid *_ttdtme;
66 // These should be in a .h file...?
68 static const char *_Tt_categories[] = {
80 // Create a message addressed to our commissioner
83 _ttDesktopMessageCreate(
84 Tt_message commission,
88 _TtDtMessageCB toolkitCB,
93 const char *_handler = handler;
95 if ((handler == 0) && (commission != 0)) {
96 _handler = tt_message_sender( commission );
97 fuse = (caddr_t)_handler;
99 return _ttDtPMessageCreate( commission, theClass, TT_SESSION,
100 handler, op, toolkitCB,
101 clientCB, clientData );
105 // Add commission id and send, if appropriate
108 _ttDesktopMessageFinish(
110 Tt_message commission,
114 _TttkItem2Free fuse = msg;
116 if (commission != 0) {
117 char *id = _tttk_message_id( commission );
118 status = tt_message_arg_add( msg, TT_IN, Tttk_message_id, id );
120 if (status != TT_OK) {
121 return (Tt_message)tt_error_pointer( status );
125 status = tt_message_send( msg );
126 if (status != TT_OK) {
127 return (Tt_message)tt_error_pointer( status );
135 // Add commission id and register in session, if appropriate
138 _ttDesktopPatternFinish(
140 Tt_message commission,
144 _TttkItem2Free fuse = pat;
146 if (commission != 0) {
147 char *id = _tttk_message_id( commission );
148 status = tt_pattern_arg_add( pat, TT_IN, Tttk_message_id, id );
150 if (status != TT_OK) {
151 return (Tt_pattern)tt_error_pointer( status );
153 tt_pattern_user_set( pat, _TttkContractKey, commission );
156 status = tt_pattern_register( pat );
157 if (status != TT_OK) {
158 return (Tt_pattern)tt_error_pointer( status );
166 // Returns widget if it is a realized shell and mappedWhenManaged, else 0
169 _ttdt_realized_widget(
171 int mappedWhenManaged_Shell
174 Widget _widget = (Widget)widget;
175 if (_widget == 0) return _widget;
176 if ((! _tt_load_xt()) || (! _tt_load_xlib())) {
179 if (! CALLXT(XtIsRealized)( _widget )) {
182 if (! mappedWhenManaged_Shell) {
185 Boolean mappedWhenManaged = False;
186 CALLXT(XtVaGetValues)( _widget,
187 XtNmappedWhenManaged, &mappedWhenManaged, 0 );
188 if (! mappedWhenManaged) {
193 WidgetClass shellClass =
194 (WidgetClass)XTSYM(applicationShellWidgetClass);
195 if (CALLXT(XtIsSubclass)( _widget, shellClass )) { // XXX never true!?
203 // Parse a request and pass it to the user's contract callback.
213 Ttdt_contract_cb _cb = (Ttdt_contract_cb)clientCB;
214 char *opString = tt_message_op( msg );
215 Tttk_op op = tttk_string_op( opString );
217 Boolean sensitive = True;
219 static Atom wmProtocols = 0;
220 static Atom wmDeleteWindow = 0;
225 XClientMessageEvent ev;
226 case TTDT_GET_STATUS:
227 // Fill in the answers we know
228 tt_message_arg_val_set( msg, 1, _ttdtme->vendor() );
229 tt_message_arg_val_set( msg, 2, _ttdtme->toolname() );
230 tt_message_arg_val_set( msg, 3, _ttdtme->version() );
238 widget = _ttdt_realized_widget( clientData );
240 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
243 dpy = (Display *)CALLXT(XtDisplay)( widget );
244 win = CALLXT(XtWindow)( widget );
246 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
251 silent = _tttk_message_arg_ival( msg, 0, 0 );
252 force = _tttk_message_arg_ival( msg, 0, 0 );
253 if (silent || force) {
255 // tttk cannot guarantee that the application
256 // will neither block on user input nor
257 // cancel the WM_DELETE_WINDOW
259 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP,
263 ev.type = ClientMessage;
265 if (wmProtocols == 0) {
266 wmProtocols = CALLX11(XInternAtom)( dpy,
267 "WM_PROTOCOLS", False );
268 wmDeleteWindow = CALLX11(XInternAtom)( dpy,
269 "WM_DELETE_WINDOW", False );
271 ev.message_type = wmProtocols;
273 ev.data.l[0] = wmDeleteWindow;
274 ev.data.l[1] = 0; //XtLastTimestampProcessed?
275 CALLX11(XSendEvent)( dpy, win, False, 0L, (XEvent*)&ev );
276 tt_message_reply( msg );
277 tt_message_destroy( msg );
282 if (CALLXT(XtIsSensitive)( widget ) == sensitive) {
283 tt_message_status_set(msg,TT_DESKTOP_EALREADY);
285 CALLXT(XtSetSensitive)( widget, sensitive );
287 tt_message_reply( msg );
288 tt_message_destroy( msg );
296 return (*_cb)( msg, clientData, _tttk_pattern_contract( pat ) );
300 // Create a pattern for a desktop message
305 _TtDtMessageCB internalCB,
306 Tt_category category,
307 Tt_message commission,
313 Tt_pattern pat = _ttDtPatternCreate( category, TT_SESSION,
315 internalCB, clientCB,
317 Tt_status status = tt_ptr_error( pat );
318 if (status != TT_OK) {
321 _TttkItem2Free fuse = pat;
322 Tt_mode mode = TT_OUT;
327 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
328 if (status != TT_OK) {
329 return (Tt_pattern)tt_error_pointer( status );
331 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
332 if (status != TT_OK) {
333 return (Tt_pattern)tt_error_pointer( status );
335 status = tt_pattern_arg_add( pat, mode, Tttk_integer, 0 );
336 if (status != TT_OK) {
337 return (Tt_pattern)tt_error_pointer( status );
340 case TTDT_SET_GEOMETRY:
342 case TTDT_GET_GEOMETRY:
343 status = tt_pattern_arg_add( pat, mode, Tttk_width, 0 );
344 if (status != TT_OK) {
345 return (Tt_pattern)tt_error_pointer( status );
347 status = tt_pattern_arg_add( pat, mode, Tttk_height, 0 );
348 if (status != TT_OK) {
349 return (Tt_pattern)tt_error_pointer( status );
351 status = tt_pattern_arg_add( pat, mode, Tttk_xoffset, 0 );
352 if (status != TT_OK) {
353 return (Tt_pattern)tt_error_pointer( status );
355 status = tt_pattern_arg_add( pat, mode, Tttk_yoffset, 0 );
356 if (status != TT_OK) {
357 return (Tt_pattern)tt_error_pointer( status );
360 case TTDT_SET_ICONIFIED:
362 case TTDT_GET_ICONIFIED:
363 status = tt_pattern_arg_add( pat, mode, Tttk_boolean, 0 );
364 if (status != TT_OK) {
365 return (Tt_pattern)tt_error_pointer( status );
369 status = tt_pattern_arg_add( pat, TT_IN, Tttk_boolean, 0 );
370 if (status != TT_OK) {
371 return (Tt_pattern)tt_error_pointer( status );
373 status = tt_pattern_arg_add( pat, TT_IN, Tttk_boolean, 0 );
374 if (status != TT_OK) {
375 return (Tt_pattern)tt_error_pointer( status );
380 case TTDT_GET_STATUS:
381 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
382 if (status != TT_OK) {
383 return (Tt_pattern)tt_error_pointer( status );
385 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
386 if (status != TT_OK) {
387 return (Tt_pattern)tt_error_pointer( status );
389 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
390 if (status != TT_OK) {
391 return (Tt_pattern)tt_error_pointer( status );
393 status = tt_pattern_arg_add( pat, mode, Tttk_string, 0 );
394 if (status != TT_OK) {
395 return (Tt_pattern)tt_error_pointer( status );
398 case TTDT_DO_COMMAND:
399 status = tt_pattern_arg_add( pat, TT_IN, Tttk_string, 0 );
400 if (status != TT_OK) {
401 return (Tt_pattern)tt_error_pointer( status );
403 status = tt_pattern_arg_add( pat, TT_OUT, Tttk_string, 0 );
404 if (status != TT_OK) {
405 return (Tt_pattern)tt_error_pointer( status );
414 return _ttDesktopPatternFinish( pat, commission, register_it );
421 const char *toolName,
427 Tt_message msg = tttk_message_create( context, TT_NOTICE, TT_SESSION, 0,
429 Tt_status status = tt_ptr_error( msg );
430 if (status != TT_OK) {
433 tt_message_arg_add( msg, TT_IN, Tttk_string, toolName );
434 tt_message_arg_add( msg, TT_IN, Tttk_string, vendor );
435 tt_message_arg_add( msg, TT_IN, Tttk_string, version );
436 if (! sendAndDestroy) {
439 status = tt_message_send( msg );
440 if (status != TT_OK) {
441 tttk_message_destroy( msg );
442 return (Tt_message)tt_error_pointer( status );
444 tttk_message_destroy( msg );
451 const char *toolName,
457 return _ttDtStarted( TTDT_STARTED, context, toolName, vendor, version,
464 const char *toolName,
470 return _ttDtStarted( TTDT_STOPPED, context, toolName, vendor, version,
477 Tt_message commission,
478 const char *statusString,
479 const char *toolName,
486 if (commission != 0) {
487 handler = tt_message_sender( commission );
489 Tt_message msg = _ttDtPMessageCreate( context, TT_NOTICE, TT_SESSION,
490 handler, TTDT_STATUS, 0, 0, 0 );
492 Tt_status status = tt_ptr_error( msg );
493 if (status != TT_OK) {
496 tt_message_arg_add( msg, TT_IN, Tttk_string, statusString );
497 tt_message_arg_add( msg, TT_IN, Tttk_string, toolName );
498 tt_message_arg_add( msg, TT_IN, Tttk_string, vendor );
499 tt_message_arg_add( msg, TT_IN, Tttk_string, version );
500 msg = _ttDesktopMessageFinish( msg, commission, sendAndDestroy );
501 status = tt_ptr_error( msg );
502 if (sendAndDestroy && (tt_ptr_error( msg ) == TT_OK)) {
503 tttk_message_destroy( msg );
510 // Returns X11 geometry of a widget
521 if ((! _tt_load_xt()) || (! _tt_load_xlib())) {
524 XWindowAttributes attrs;
526 Display *dpy = (Display *)CALLXT(XtDisplay)( widget );
527 Window win = CALLXT(XtWindow)( widget );
529 if (! CALLX11(XGetWindowAttributes)( dpy, win, &attrs )) {
532 // XXX x,y still seem to be a little off
533 CALLX11(XTranslateCoordinates)( dpy, win, attrs.root,
536 &rx, &ry, &junkwin );
545 // Help out on Set_Geometry requests and edicts
548 _ttdt_do_Set_Geometry(
557 _TttkItem2Free fuse = msg;
558 Widget widget = _ttdt_realized_widget( clientData );
560 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
563 int newX, newY, newW, newH;
564 if (! _ttXGetGeometry( widget, &newW, &newH, &newX, &newY )) {
565 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
574 if (*xOffset != INT_MAX) {
577 if (*yOffset != INT_MAX) {
580 CALLX11(XMoveResizeWindow)( CALLXT(XtDisplay)( widget),
581 CALLXT(XtWindow)( widget ),
582 newX, newY, newW, newH );
588 // Pattern callback for {GS}et_Geometry requests and Set_Geometry edicts
591 _ttdt_do_GSet_Geometry(
601 _TttkItem2Free fuse = msg;
602 Widget widget = _ttdt_realized_widget( clientData );
604 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
607 char *ops = tt_message_op( msg );
608 Tttk_op op = tttk_string_op( ops );
611 if ( op == TTDT_SET_GEOMETRY) {
612 msg = _ttdt_do_Set_Geometry( msg, clientData, width,
613 height, xOffset, yOffset );
614 status = tt_ptr_error( msg );
615 if ((status != TT_OK) || (msg == 0)) {
620 if (! _ttXGetGeometry( widget, &w, &h, &x, &y )) {
621 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
633 // Parse Get_Geometry reply and pass it to user callback.
636 _ttdt_Geometry_in_cb(
643 if (! _tttk_message_in_final_state( msg )) {
644 // Not in final state; our address space is probably handler
647 _TttkItem2Free fuse = msg;
648 int width = _tttk_message_arg_ival( msg, 0, -1 );
649 int height = _tttk_message_arg_ival( msg, 1, -1 );
650 int xOffset = _tttk_message_arg_ival( msg, 2, INT_MAX );
651 int yOffset = _tttk_message_arg_ival( msg, 3, INT_MAX );
652 Ttdt_Geometry_in_cb _cb = (Ttdt_Geometry_in_cb)clientCB;
653 fuse = (caddr_t)0; // prevent message destruction
655 // A Ttdt_Geometry_in_cb is never involved in a pattern,
656 // so contract is always 0.
658 msg = (*_cb)( msg, clientData, 0, width, height, xOffset, yOffset );
663 // Create and optionally send a {GS}et_Geometry request or edict
669 Tt_message commission,
671 Ttdt_Geometry_in_cb callback,
680 Tt_message msg = _ttDesktopMessageCreate( commission, theClass,
681 handler, op, _ttdt_Geometry_in_cb,
682 callback, clientdata );
683 Tt_status status = tt_ptr_error( msg );
684 if (status != TT_OK) {
687 _TttkItem2Free fuse = msg;
688 if (op == TTDT_GET_GEOMETRY) {
689 status = tt_message_arg_add( msg, TT_OUT, Tttk_width, 0 );
690 if (status != TT_OK) {
691 return (Tt_message)tt_error_pointer( status );
693 status = tt_message_arg_add( msg, TT_OUT, Tttk_height, 0 );
694 if (status != TT_OK) {
695 return (Tt_message)tt_error_pointer( status );
697 status = tt_message_arg_add( msg, TT_OUT, Tttk_xoffset, 0 );
698 if (status != TT_OK) {
699 return (Tt_message)tt_error_pointer( status );
701 status = tt_message_arg_add( msg, TT_OUT, Tttk_yoffset, 0 );
702 if (status != TT_OK) {
703 return (Tt_message)tt_error_pointer( status );
706 status = tt_message_iarg_add( msg, TT_INOUT, Tttk_width, w );
707 if (status != TT_OK) {
708 return (Tt_message)tt_error_pointer( status );
710 status = tt_message_iarg_add( msg, TT_INOUT, Tttk_height, h );
711 if (status != TT_OK) {
712 return (Tt_message)tt_error_pointer( status );
714 status = tt_message_iarg_add( msg, TT_INOUT, Tttk_xoffset, x );
715 if (status != TT_OK) {
716 return (Tt_message)tt_error_pointer( status );
718 status = tt_message_iarg_add( msg, TT_INOUT, Tttk_yoffset, y );
719 if (status != TT_OK) {
720 return (Tt_message)tt_error_pointer( status );
724 return _ttDesktopMessageFinish( msg, commission, send );
730 Tt_message commission,
731 Ttdt_Geometry_in_cb callback,
736 return _ttdt_GSet_Geometry( TTDT_GET_GEOMETRY, handler, commission,
737 TT_REQUEST, callback, clientdata,
744 Tt_message commission,
746 Ttdt_Geometry_in_cb callback,
755 return _ttdt_GSet_Geometry( TTDT_SET_GEOMETRY, handler, commission,
756 theClass, callback, clientdata,
757 width, height, xoffset, yoffset, send );
761 // Parse {GS}et_Geometry request, pass it to user callback,
762 // and optionally fill in and send the reply.
765 _ttdt_Geometry_out_cb(
772 _TttkItem2Free fuse = msg;
773 int width = _tttk_message_arg_ival( msg, 0, -1 );
774 int height = _tttk_message_arg_ival( msg, 1, -1 );
775 int xOffset = _tttk_message_arg_ival( msg, 2, INT_MAX );
776 int yOffset = _tttk_message_arg_ival( msg, 3, INT_MAX );
777 Ttdt_Geometry_out_cb _cb = (Ttdt_Geometry_out_cb)clientCB;
778 Tt_message contract = _tttk_pattern_contract( pat );
779 msg = (*_cb)( msg, clientData, contract, &width, &height, &xOffset,
781 Tt_status status = tt_ptr_error( msg );
782 if ((status != TT_OK) || (msg == 0)) {
783 // user already replied or failed, and destroyed
788 tt_message_arg_ival_set( msg, 0, width );
791 tt_message_arg_ival_set( msg, 1, height );
793 if (xOffset != INT_MAX) {
794 tt_message_arg_ival_set( msg, 2, xOffset );
796 if (yOffset != INT_MAX) {
797 tt_message_arg_ival_set( msg, 3, yOffset );
799 status = _tttk_message_reply( msg );
800 if (status != TT_OK) {
801 return (Tt_message)tt_error_pointer( status );
807 ttdt_Set_Geometry_pat(
808 Tt_category category,
809 Tt_message commission,
810 Ttdt_Geometry_out_cb callback,
815 return _ttdt_pat( TTDT_SET_GEOMETRY, _ttdt_Geometry_out_cb,
816 category, commission,
817 callback, clientdata, register_it );
821 ttdt_Get_Geometry_pat(
822 Tt_category category,
823 Tt_message commission,
824 Ttdt_Geometry_out_cb callback,
829 return _ttdt_pat( TTDT_GET_GEOMETRY, _ttdt_Geometry_out_cb,
830 category, commission,
831 callback, clientdata, register_it );
840 // XXX XtNiconic always returns false?!
841 CALLXT(XtVaGetValues)( widget, XtNiconic, &iconic, 0 );
842 return (iconic == TRUE);
846 // Pattern callback for {GS}et_Iconified, {GS}et_Mapped requests and edicts
853 int *iconified_or_mapped
856 Widget widget = _ttdt_realized_widget( clientData );
858 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
861 char *ops = tt_message_op( msg );
862 Tttk_op op = tttk_string_op( ops );
864 Display *dpy = (Display *)CALLXT(XtDisplay)( widget );
865 Window win = CALLXT(XtWindow)( widget );
868 XWindowAttributes attribs;
870 case TTDT_SET_ICONIFIED:
871 CALLX11(XGetWindowAttributes)( dpy, win, &attribs );
872 if (*iconified_or_mapped) {
873 int screen = CALLX11(XScreenNumberOfScreen)(
875 CALLX11(XIconifyWindow)( dpy, win, screen );
877 CALLX11(XRaiseWindow)( dpy, win ); // or XMapRaised?
879 // Fall through, to see if it worked
880 case TTDT_GET_ICONIFIED:
881 iconic = _ttdt_is_iconic( widget );
882 if ( (op == TTDT_SET_ICONIFIED)
883 && (*iconified_or_mapped != iconic))
885 tttk_message_fail( msg, TT_ERR_ACCESS, 0, 0 );
888 *iconified_or_mapped = iconic;
890 case TTDT_SET_MAPPED:
891 CALLX11(XGetWindowAttributes)( dpy, win, &attribs );
892 if (*iconified_or_mapped) {
893 CALLX11(XMapWindow)( dpy, win );
895 int screen = CALLX11(XScreenNumberOfScreen)(
897 CALLX11(XWithdrawWindow)( dpy, win, screen );
899 // Fall through, to see if it worked
900 case TTDT_GET_MAPPED:
901 CALLX11(XGetWindowAttributes)( dpy, win, &attribs );
902 mapped = attribs.map_state != IsUnmapped;
903 if ( (op == TTDT_SET_ICONIFIED)
904 && (*iconified_or_mapped != mapped))
906 tttk_message_fail( msg, TT_ERR_ACCESS, 0, 0 );
909 *iconified_or_mapped = mapped;
916 // Parse Get_Iconified reply and pass it to user callback.
919 _ttdt_Iconified_in_cb(
926 if (! _tttk_message_in_final_state( msg )) {
927 // Not in final state; our address space is probably handler
930 _TttkItem2Free fuse = msg;
931 int iconified = _tttk_message_arg_ival( msg, 0, 0 );
932 Ttdt_Iconified_in_cb _cb = (Ttdt_Iconified_in_cb)clientCB;
933 fuse = (caddr_t)0; // prevent message destruction
934 msg = (*_cb)( msg, clientData, _tttk_pattern_contract( pat ),
940 // Create and optionally send a {GS}et_Iconified request or edict
943 _ttdt_GSet_Iconified(
946 Tt_message commission,
948 Ttdt_Iconified_in_cb callback,
954 Tt_message msg = _ttDesktopMessageCreate( commission, theClass,
955 handler, op, _ttdt_Iconified_in_cb,
956 callback, clientdata );
957 Tt_status status = tt_ptr_error( msg );
958 if (status != TT_OK) {
961 _TttkItem2Free fuse = msg;
962 if (op == TTDT_GET_ICONIFIED) {
963 status = tt_message_arg_add( msg, TT_OUT, Tttk_boolean, 0 );
964 if (status != TT_OK) {
965 return (Tt_message)tt_error_pointer( status );
968 status = tt_message_iarg_add( msg, TT_IN, Tttk_boolean,
970 if (status != TT_OK) {
971 return (Tt_message)tt_error_pointer( status );
975 return _ttDesktopMessageFinish( msg, commission, send );
981 Tt_message commission,
982 Ttdt_Iconified_in_cb callback,
987 return _ttdt_GSet_Iconified( TTDT_GET_ICONIFIED, handler, commission,
988 TT_REQUEST, callback, clientdata,
995 Tt_message commission,
997 Ttdt_Iconified_in_cb callback,
1003 return _ttdt_GSet_Iconified( TTDT_SET_ICONIFIED, handler, commission,
1004 theClass, callback, clientdata,
1009 // Parse {GS}et_Iconified request, pass it to user callback,
1010 // and optionally fill in and send the reply.
1013 _ttdt_Iconified_out_cb(
1020 _TttkItem2Free fuse = msg;
1021 int iconified = _tttk_message_arg_ival( msg, 0, 0 );
1022 Ttdt_Iconified_out_cb _cb = (Ttdt_Iconified_out_cb)clientCB;
1023 msg = (*_cb)( msg, clientData, _tttk_pattern_contract( pat ),
1025 Tt_status status = tt_ptr_error( msg );
1026 if ((status != TT_OK) || (msg == 0)) {
1027 // user already replied or failed, and destroyed
1031 tt_message_arg_ival_set( msg, 0, iconified );
1032 status = _tttk_message_reply( msg );
1033 if (status != TT_OK) {
1034 return (Tt_message)tt_error_pointer( status );
1040 ttdt_Set_Iconified_pat(
1041 Tt_category category,
1042 Tt_message commission,
1043 Ttdt_Iconified_out_cb callback,
1049 return _ttdt_pat( TTDT_SET_ICONIFIED, _ttdt_Iconified_out_cb,
1050 category, commission,
1051 callback, clientdata, register_it );
1055 ttdt_Get_Iconified_pat(
1056 Tt_category category,
1057 Tt_message commission,
1058 Ttdt_Iconified_out_cb callback,
1063 return _ttdt_pat( TTDT_GET_ICONIFIED, _ttdt_Iconified_out_cb,
1064 category, commission,
1065 callback, clientdata, register_it );
1069 // Pattern callback for Set_XInfo requests
1082 tttk_message_fail( msg, TT_ERR_POINTER, 0, 0 );
1083 tttk_message_destroy( msg );
1087 // Cannot change the X display of a widget,
1088 // so just set $DISPLAY
1090 _tt_putenv( "DISPLAY", display );
1095 // Map the name of an X11 visual to a visual #defined in X.h
1097 static const char *_ttdt_visuals[] = {
1108 const char *visualName
1111 if (visualName == 0) {
1114 for (int visual = StaticGray; visual <= DirectColor; visual++) {
1115 if (strcmp( visualName, _ttdt_visuals[visual] ) == 0) {
1127 if ((visual < StaticGray) || (visual > DirectColor)) {
1130 return _ttdt_visuals[ visual ];
1134 // Pattern callback for Get_XInfo requests
1146 _TttkItem2Free fuse = msg;
1147 Widget widget = _ttdt_realized_widget( _widget, 0 );
1149 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 0 );
1152 Display *dpy = (Display *)CALLXT(XtDisplay)( widget );
1153 *display = DisplayString( dpy );
1154 if (*display == 0) {
1155 tttk_message_fail( msg, TT_ERR_INTERNAL,
1156 "DisplayString() == 0", 0 );
1160 char *display_and_screen;
1161 if ((*display)[0] == ':') {
1162 display_and_screen = *display;
1164 } else if (strncmp(*display, "unix:", 5) == 0) {
1165 display_and_screen = (*display)+4; // !5; we want the colon
1169 _Tt_string portable_display = _tt_gethostname();
1170 portable_display = portable_display.cat(display_and_screen);
1171 *display = _tt_strdup((char *)portable_display);
1173 *display = _tt_strdup( *display );
1175 *visual = DefaultVisualOfScreen(
1176 DefaultScreenOfDisplay( dpy ))->c_class;
1177 *depth = DefaultDepthOfScreen( DefaultScreenOfDisplay( dpy ));
1183 // Parse Get_XInfo reply and pass it to user callback.
1193 if (! _tttk_message_in_final_state( msg )) {
1194 // Not in final state; our address space is probably handler
1197 _TttkItem2Free fuse = msg;
1198 char *display = _tttk_message_arg_val( msg, 0, 0 );
1199 char *visual = _tttk_message_arg_val( msg, 1, 0 );
1200 int _visual = _ttDtVisual( visual );
1202 int depth = _tttk_message_arg_ival( msg, 2, 0 );
1203 Ttdt_XInfo_in_cb _cb = (Ttdt_XInfo_in_cb)clientCB;
1204 fuse = (caddr_t)0; // prevent message destruction
1205 msg = (*_cb)( msg, clientData, _tttk_pattern_contract( pat ),
1206 display, _visual, depth );
1211 // Create and optionally send a {GS}et_XInfo request or edict
1216 const char *handler,
1217 Tt_message commission,
1219 Ttdt_XInfo_in_cb callback,
1221 const char *display,
1227 Tt_message msg = _ttDesktopMessageCreate( commission, theClass,
1228 handler, op, _ttdt_XInfo_in_cb,
1229 callback, clientdata );
1230 Tt_status status = tt_ptr_error( msg );
1231 if (status != TT_OK) {
1234 _TttkItem2Free fuse = msg;
1235 if (op == TTDT_GET_XINFO) {
1236 status = tt_message_arg_add( msg, TT_OUT, Tttk_string, 0 );
1237 if (status != TT_OK) {
1238 return (Tt_message)tt_error_pointer( status );
1240 status = tt_message_arg_add( msg, TT_OUT, Tttk_string, 0 );
1241 if (status != TT_OK) {
1242 return (Tt_message)tt_error_pointer( status );
1244 status = tt_message_arg_add( msg, TT_OUT, Tttk_integer, 0 );
1245 if (status != TT_OK) {
1246 return (Tt_message)tt_error_pointer( status );
1249 status = tt_message_arg_add( msg, TT_IN, Tttk_string, display);
1250 if (status != TT_OK) {
1251 return (Tt_message)tt_error_pointer( status );
1253 status = tt_message_arg_add( msg, TT_IN, Tttk_string,
1254 _ttDtVisualString( visual ));
1255 if (status != TT_OK) {
1256 return (Tt_message)tt_error_pointer( status );
1258 status = tt_message_iarg_add( msg, TT_INOUT, Tttk_integer,
1260 if (status != TT_OK) {
1261 return (Tt_message)tt_error_pointer( status );
1265 return _ttDesktopMessageFinish( msg, commission, send );
1270 const char *handler,
1271 Tt_message commission,
1272 Ttdt_XInfo_in_cb callback,
1277 return _ttdt_GSet_XInfo( TTDT_GET_XINFO, handler, commission,
1278 TT_REQUEST, callback, clientdata,
1284 const char *handler,
1285 Tt_message commission,
1287 Ttdt_XInfo_in_cb callback,
1289 const char *display,
1295 return _ttdt_GSet_XInfo( TTDT_SET_XINFO, handler, commission,
1296 theClass, callback, clientdata,
1297 display, visual, depth, send );
1301 // Parse {GS}et_XInfo request, pass it to user callback,
1302 // and optionally fill in and send the reply.
1312 _TttkItem2Free fuse = msg;
1313 char *display = _tttk_message_arg_val( msg, 0, 0 );
1314 char *_visual = _tttk_message_arg_val( msg, 1, 0 );
1315 int visual = _ttDtVisual( _visual );
1317 int depth = _tttk_message_arg_ival( msg, 2, 1 );
1318 Ttdt_XInfo_out_cb _cb = (Ttdt_XInfo_out_cb)clientCB;
1319 msg = (*_cb)( msg, clientData, _tttk_pattern_contract( pat ),
1320 &display, &visual, &depth );
1321 Tt_status status = tt_ptr_error( msg );
1322 if ((status != TT_OK) || (msg == 0)) {
1323 // user already replied or failed, and destroyed
1327 tt_message_arg_val_set( msg, 0, display );
1328 tt_message_arg_val_set( msg, 1, _ttDtVisualString( visual ));
1329 tt_message_arg_ival_set( msg, 2, depth );
1330 status = _tttk_message_reply( msg );
1331 if (status != TT_OK) {
1332 return (Tt_message)tt_error_pointer( status );
1339 Tt_category category,
1340 Tt_message commission,
1341 Ttdt_XInfo_in_cb callback,
1346 return _ttdt_pat( TTDT_SET_XINFO, _ttdt_XInfo_out_cb,
1347 category, commission,
1348 callback, clientdata, register_it );
1353 Tt_category category,
1354 Tt_message commission,
1355 Ttdt_XInfo_out_cb callback,
1360 return _ttdt_pat( TTDT_GET_XINFO, _ttdt_XInfo_out_cb,
1361 category, commission,
1362 callback, clientdata, register_it );
1366 // Parse Get_Locale reply and pass it to user callback.
1367 // Also used to parse Set_Locale request and pass it to _ttDtApplyLocale().
1377 _TttkItem2Free fuse = msg;
1378 int numArgs = tt_message_args_count( msg );
1379 Tt_status status = tt_int_error( numArgs );
1380 if (status != TT_OK) {
1381 return (Tt_message)tt_error_pointer( status );
1383 _TttkList2Free fuses( numArgs + 2 );
1384 int n = numArgs / 2;
1385 char **categories = (char **)tt_malloc( (n + 1) * sizeof(char *) );
1386 char **locales = (char **)tt_malloc( (n + 1) * sizeof(char *) );
1387 categories[ n ] = 0;
1390 // We only need these guys until after we call clientCB
1392 fuses += (caddr_t)categories;
1393 fuses += (caddr_t)locales;
1394 for (int i = 0; i < n; i++) {
1395 categories[i] = tt_message_arg_val( msg, 2 * i );
1396 status = tt_ptr_error( categories[i] );
1397 if (status != TT_OK) {
1398 return (Tt_message)tt_error_pointer( status );
1400 fuses += categories[i];
1401 locales[i] = tt_message_arg_val( msg, 2 * i + 1 );
1402 status = tt_ptr_error( locales[i] );
1403 if (status != TT_OK) {
1404 return (Tt_message)tt_error_pointer( status );
1406 fuses += locales[i];
1408 fuse = (caddr_t)0; // aborts message destruction
1409 Ttdt_Get_Locale_msg_cb _cb = (Ttdt_Get_Locale_msg_cb)clientCB;
1410 return (*_cb)( msg, clientData,
1411 (const char **)categories,
1412 (const char **)locales );
1416 // Map a locale category name to a locale #defined in locale.h
1420 const char *categoryName
1423 if (categoryName == 0) {
1427 if (strcmp( categoryName, "LC_CTYPE" ) == 0) {
1428 category = LC_CTYPE;
1429 } else if (strcmp( categoryName, "LC_NUMERIC" ) == 0) {
1430 category = LC_NUMERIC;
1431 } else if (strcmp( categoryName, "LC_TIME" ) == 0) {
1433 } else if (strcmp( categoryName, "LC_COLLATE" ) == 0) {
1434 category = LC_COLLATE;
1435 } else if (strcmp( categoryName, "LC_MONETARY" ) == 0) {
1436 category = LC_MONETARY;
1437 } else if (strcmp( categoryName, "LC_MESSAGES" ) == 0) {
1438 category = LC_MESSAGES;
1439 } else if (strcmp( categoryName, "LC_ALL" ) == 0) {
1446 // A callback used internally that sets the locales of this
1447 // address space. If clientData is non-zero, assumes it is a
1454 const char **categories,
1455 const char **locales
1458 DisplayInfo *info = (DisplayInfo *)clientData;
1460 info->repliesOutStanding--;
1463 while (categories[ i ] != 0) {
1464 int category = _ttDtCategory( categories[ i ] );
1465 if (category != -1) {
1466 setlocale( category, locales[ i ] );
1468 tt_free( (caddr_t)categories[ i ] );
1469 tt_free( (caddr_t)locales[ i ] );
1472 tt_free( (caddr_t)categories );
1473 tt_free( (caddr_t)locales );
1474 if (_tttk_message_am_handling( msg )) {
1475 // We are being used as a pattern callback
1476 tt_message_reply( msg );
1478 tttk_message_destroy( msg );
1483 // If clientCB is 0, uses _ttDtApplyLocale, q.v. re clientData.
1487 const char *handler,
1488 Tt_message commission,
1489 Ttdt_Get_Locale_msg_cb clientCB,
1491 const char **categories,
1495 const char *_handler = handler;
1496 if ((handler == 0) && (commission != 0)) {
1497 _handler = tt_message_sender( commission );
1499 if (clientCB == 0) {
1500 clientCB = _ttDtApplyLocale;
1502 Tt_message msg = _ttDtPMessageCreate( commission, TT_REQUEST,
1503 TT_SESSION, handler,
1504 TTDT_GET_LOCALE, _ttDtGetLocaleCB, clientCB,
1506 Tt_status status = tt_ptr_error( msg );
1507 if (status != TT_OK) {
1511 // Guarantees that msg will be destroyed when this function returns
1513 _TttkItem2Free fuse = msg;
1514 const char **_cats = categories;
1516 _cats = _Tt_categories;
1518 while (*_cats != 0) {
1519 status = tt_message_arg_add( msg, TT_IN, Tttk_string, *_cats );
1520 if (status != TT_OK) {
1521 return (Tt_message)tt_error_pointer( status );
1523 status = tt_message_arg_add( msg, TT_OUT, Tttk_string, 0 );
1524 if (status != TT_OK) {
1525 return (Tt_message)tt_error_pointer( status );
1530 status = tt_message_send( msg );
1531 if (status != TT_OK) {
1532 return (Tt_message)tt_error_pointer( status );
1540 // A TtDtGetSituationMsgCB used internally to chdir() to the path
1541 // returned in a reply to Get_Situation. If clientData is nonzero,
1542 // assumes it is a DisplayInfo *.
1545 _ttDtApplySituation(
1551 DisplayInfo *info = (DisplayInfo *)clientData;
1553 info->repliesOutStanding--;
1555 if ((cwd != 0) && (chdir( cwd ) != 0)) {
1556 _tt_syslog( 0, LOG_ERR, "_ttDtApplySituation(): "
1557 "chdir( %s ): %m", cwd );
1559 tt_free( (char *)cwd );
1560 if (_tttk_message_am_handling( msg )) {
1561 // We are being used as a pattern callback
1562 tt_message_reply( msg );
1564 tttk_message_destroy( msg );
1569 // Parse Get_Situation reply and pass it to user callback
1572 _ttDtGetSituationCB(
1579 if (! _tttk_message_in_final_state( msg )) {
1580 // Not in final state; our address space is probably handler
1583 _TttkItem2Free fuse = msg;
1584 char *cwd = tt_message_arg_val( msg, 0 );
1585 Tt_status status = tt_ptr_error( cwd );
1586 if (status != TT_OK) {
1587 return (Tt_message)tt_error_pointer( status );
1589 Ttdt_Get_Situation_msg_cb _cb = (Ttdt_Get_Situation_msg_cb)clientCB;
1590 msg = (*_cb)( msg, clientData, cwd );
1591 fuse = (caddr_t)0; // prevent message destruction
1596 // If clientCB is 0, uses _ttDtApplySituation, q.v. re clientData.
1600 const char *handler,
1601 Tt_message commission,
1602 Ttdt_Get_Situation_msg_cb clientCB,
1607 const char *_handler = handler;
1608 if ((handler == 0) && (commission != 0)) {
1609 _handler = tt_message_sender( commission );
1611 if (clientCB == 0) {
1612 clientCB = _ttDtApplySituation;
1614 Tt_message msg = _ttDtPMessageCreate( commission, TT_REQUEST,
1615 TT_SESSION, _handler,
1616 TTDT_GET_SITUATION, _ttDtGetSituationCB,
1617 clientCB, clientData );
1618 Tt_status status = tt_ptr_error( msg );
1619 if (status != TT_OK) {
1623 // Guarantees that msg will be destroyed when this function returns
1625 _TttkItem2Free fuse = msg;
1626 status = tt_message_arg_add( msg, TT_OUT, Tttk_string, 0 );
1627 if (status != TT_OK) {
1628 return (Tt_message)tt_error_pointer( status );
1631 status = tt_message_send( msg );
1632 if (status != TT_OK) {
1633 return (Tt_message)tt_error_pointer( status );
1641 // Handle a POSIX-related Desktop request
1650 { char *opString = tt_message_op( msg );
1651 Tttk_op op = tttk_string_op( opString );
1652 tt_free( opString );
1653 int numArgs = tt_message_args_count( msg );
1654 Tt_status status = tt_int_error( numArgs );
1655 if (status != TT_OK) {
1656 return (Tt_message)tt_error_pointer( status );
1659 char *categoryName, *variable, *value;
1661 struct utsname names;
1662 char buf[ SYS_NMLN ];
1663 case TTDT_SET_LOCALE:
1664 return _ttDtGetLocaleCB( msg, pat, _ttDtApplyLocale, 0 );
1665 case TTDT_GET_LOCALE:
1666 for (i = 0; i < numArgs/2; i++) {
1667 categoryName = _tttk_message_arg_val( msg, 2 * i, 0 );
1668 if (categoryName == 0) {
1671 category = _ttDtCategory( categoryName );
1673 tt_message_arg_val_set( msg, 2 * i + 1,
1674 setlocale( category, 0 ));
1676 tt_free( categoryName );
1678 tt_message_reply( msg );
1679 tttk_message_destroy( msg );
1681 case TTDT_SET_ENVIRONMENT:
1682 case TTDT_GET_ENVIRONMENT:
1683 for (i = 0; i < numArgs/2; i++) {
1684 variable = _tttk_message_arg_val( msg, 2 * i, 0 );
1685 if (variable == 0) {
1688 if (op == TTDT_GET_ENVIRONMENT) {
1689 tt_message_arg_val_set( msg, 2 * i + 1,
1690 getenv( variable ));
1691 } else if (_tttk_message_arg_is_set( msg, 2*i+1 )) {
1692 value = _tttk_message_arg_val( msg, 2*i+1, 0 );
1693 _tt_putenv( variable, value );
1696 _tt_putenv( variable, 0 );
1698 tt_free( variable );
1700 tt_message_reply( msg );
1701 tttk_message_destroy( msg );
1703 case TTDT_SET_SITUATION:
1704 value = _tttk_message_arg_val( msg, 0, 0 );
1706 value = tt_message_file( msg );
1707 if (tt_ptr_error( value ) != TT_OK) {
1712 tttk_message_fail( msg, TT_DESKTOP_EPROTO, 0, 1 );
1715 if (chdir( value ) != 0) {
1717 tttk_message_fail( msg, _tt_errno_status( errno ),
1722 tt_message_reply( msg );
1723 tttk_message_destroy( msg );
1725 case TTDT_GET_SITUATION:
1726 value = getcwd( 0, MAXPATHLEN );
1728 tttk_message_fail( msg, _tt_errno_status( errno ),
1732 status = tt_message_arg_val_set( msg, 0, value );
1734 if (status != TT_OK) {
1735 tttk_message_fail( msg, status, 0, 1 );
1738 tt_message_reply( msg );
1739 tttk_message_destroy( msg );
1742 i = _tttk_message_arg_ival( msg, 0, 0 );
1744 tttk_message_fail( msg, TT_DESKTOP_EINVAL, 0, 1 );
1747 // Reply before actually signalling, in case we die
1748 tt_message_reply( msg );
1749 tttk_message_destroy( msg );
1750 kill( getpid(), i );
1752 case TTDT_GET_SYSINFO:
1753 if (uname( &names ) < 0) {
1754 tttk_message_fail( msg, _tt_errno_status( errno ),
1758 // The first 5 values are from uname and seem pretty standard
1759 tt_message_arg_val_set( msg, 0, names.sysname );
1760 tt_message_arg_val_set( msg, 1, names.nodename );
1761 tt_message_arg_val_set( msg, 2, names.release );
1762 tt_message_arg_val_set( msg, 3, names.version );
1763 tt_message_arg_val_set( msg, 4, names.machine );
1764 // The last 3 are from sysinfo which seems to be SVR4 only.
1765 // For platforms without the sysinfo call, we just leave
1766 // the values unset for now, except for the serial
1767 // number which is available from utsname onHPUX.
1768 #if defined(OPT_SYSINFO)
1769 if (sysinfo( SI_ARCHITECTURE, buf, SYS_NMLN ) >= 0) {
1770 tt_message_arg_val_set( msg, 5, buf );
1772 if (sysinfo( SI_HW_PROVIDER, buf, SYS_NMLN ) >= 0) {
1773 tt_message_arg_val_set( msg, 6, buf );
1775 if (sysinfo( SI_HW_SERIAL, buf, SYS_NMLN ) >= 0) {
1776 tt_message_arg_val_set( msg, 7, buf );
1778 #elif defined(__hpux) || defined(hpux)
1779 tt_message_arg_val_set( msg, 7, names.idnumber);
1781 tt_message_reply( msg );
1782 tttk_message_destroy( msg );
1789 // Pattern callback for Raise, Lower requests
1792 _ttdt_do_RaiseLower(
1798 Widget widget = _ttdt_realized_widget( _widget, 0 );
1800 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 1 );
1803 char *ops = tt_message_op( msg );
1804 Tttk_op op = tttk_string_op( ops );
1806 Display *dpy = (Display *)CALLXT(XtDisplay)( widget );
1807 Window win = CALLXT(XtWindow)( widget );
1810 CALLX11(XRaiseWindow)( dpy, win );
1813 CALLX11(XLowerWindow)( dpy, win );
1816 tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 1 );
1819 _tttk_message_reply( msg );
1820 tttk_message_destroy( msg );