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: mp_desktop.C /main/7 1998/04/09 17:52:01 mgreess $
30 * @(#)mp_desktop.C 1.34 93/09/07
32 * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
36 // This file contains method for dealing with a "desktop" connection.
37 // Typically this desktop is an X11 session but this way the interface
38 // to the desktop is relatively free of Xisms allowing for more
39 // independence from X11 in the future.
43 #include "tt_options.h"
44 // Defining BSD_COMP gets us FIONREAD on SunOS 5.x, and shouldn\'t
45 // hurt in other places.
47 #include <sys/ioctl.h>
48 #include <sys/types.h>
50 #if defined(__STDC__) && !defined(linux)
51 extern "C" { extern int ioctl (int, int, ...) ; };
53 #include "util/tt_global_env.h"
54 #include "util/tt_ldpath.h"
55 #include "util/tt_host.h"
56 #include "util/tt_port.h"
57 #include "util/tt_Xlib.h"
58 #include "mp/mp_desktop.h"
62 #include "util/tt_gettext.h"
64 static int parse_Xdisplay_string(_Tt_string display,
67 _Tt_string &hostname);
70 jmp_buf _Tt_desktop::io_exception;
72 // The following private class data is declared and allocated here
73 // so that everybody that includes mp_desktop.h doesn't have to
74 // also include X11/Xlib.h.
76 struct _Tt_desktop_private {
83 priv = (_Tt_desktop_private *)malloc(sizeof(_Tt_desktop_private));
84 priv->xd = (Display *)0;
91 // Ungrab the server, in case the user
92 // interrupted us during a grab.
95 free((MALLOCTYPE *)priv);
100 // Initializes a desktop object. This has the effect of connecting to the
101 // appropiate X11 server. "dt_handle" is a string identifying which
102 // desktop we want to talk to. For X11, this string will be the same as
103 // what would be specified in the DISPLAY variable.
106 init(_Tt_string dt_handle, _Tt_dt_type /* t */)
109 _Tt_string h, hostname;
114 if (priv->xd != (Display *)0) {
118 // initialize our access to Xlib
119 if (! _tt_load_xlib()) {
125 // parse the dt_handle string to extract the host and server
126 // number information.
128 parse_status = parse_Xdisplay_string(dt_handle, h, s, hostname);
130 // Now we examine the parse status to determine if this is a
131 // local host or remote host and if we should use a unix
132 // connection or not. We also enforce the use of screen 0 for
134 switch (parse_status) {
135 case 1: // non-local host
136 case 2: // local host
137 // important to always use screen 0 for the case where
138 // multiple displays are used.
139 sprintf(buf,":%d.0",s);
140 if (dt_handle[0] == ':') {
143 display = hostname.cat(buf);
146 case 3: // local host and unix connection specified
147 sprintf(buf,"unix:%d.0", s);
151 _tt_syslog( 0, LOG_ERR,
152 catgets( _ttcatd, 1, 17,
153 "could not parse X display name: \"%s\"" ),
162 set_error_handler(_Tt_desktop::io_error_proc);
163 if (0 == setjmp(io_exception)) {
165 // now connect to the indicated X11 server
167 if (priv->xd = (Display *)
168 CALLX11(XOpenDisplay)((char *)display)) {
169 // Xlib has already emitted diagnostic
174 if (!priv->xd) ret_val = 0;
178 restore_user_handler();
183 // I/O error handler. Longjmp back to before the error occured.
185 io_error_proc(void *)
187 longjmp(io_exception, 1);
192 // Sets the error handler function which will get invoked on any I/O
193 // errors received from the X11 connection
195 set_error_handler(_Tt_dt_errfn efn)
197 user_io_handler = (int *)
198 CALLX11(XSetIOErrorHandler)((XIOErrorHandler)efn);
202 // Restore the users I/O error handler.
204 restore_user_handler()
206 CALLX11(XSetIOErrorHandler)((XIOErrorHandler)user_io_handler);
210 // Closes the connection to the X11 server.
216 set_error_handler(_Tt_desktop::io_error_proc);
217 if (0 == setjmp(io_exception)) {
219 // delete all properties set and close connection to desktop
220 if (priv->xd != (Display *)0) {
221 CALLX11(XCloseDisplay)(priv->xd);
226 restore_user_handler();
231 // Returns the fd to poll on when new events come from the desktop
236 return ConnectionNumber(priv->xd);
241 // Method to call when an event comes in from the desktop connection.
242 // This method will return 0 if the connection is broken indicating
243 // either a network partition or the X11 server going down.
253 if (priv->xd == (Display *)0) {
257 CALLX11(XFlush)(priv->xd);
259 iostat=ioctl(notify_fd(), FIONREAD, (char *)&pending);
260 if (iostat == -1 || pending == 0) {
261 // X server went down
264 if (priv->xd != (Display *)0) {
265 CALLX11(XNextEvent)(priv->xd, &xev);
266 if (xev.type == MappingNotify) {
267 xm = (XMappingEvent *)&xev;
268 CALLX11(XRefreshKeyboardMapping)(xm);
280 CALLX11(XGrabServer)(priv->xd);
281 CALLX11(XFlush)(priv->xd);
290 CALLX11(XUngrabServer)(priv->xd);
291 CALLX11(XFlush)(priv->xd);
297 // Sets the value of the indicated property name to val.
300 set_prop(_Tt_string pname, _Tt_string &val)
305 const unsigned char *v;
307 if (priv->xd == (Display *)0) {
311 patom = CALLX11(XInternAtom)(priv->xd, (char *)pname, False);
316 rootw = DefaultRootWindow(priv->xd);
318 v = (const unsigned char *)v1;
319 CALLX11(XChangeProperty)(priv->xd, rootw,
323 CALLX11(XFlush)(priv->xd);
329 // Deletes the indicated property from the desktop.
332 del_prop(_Tt_string pname)
337 if (priv->xd == (Display *)0) {
341 patom = CALLX11(XInternAtom)(priv->xd, (char *)pname, False);
346 rootw = DefaultRootWindow(priv->xd);
347 CALLX11(XDeleteProperty)(priv->xd, rootw, patom);
348 CALLX11(XFlush)(priv->xd);
355 // Gets the value of the indicated property from the desktop.
358 get_prop(_Tt_string pname, _Tt_string &pval)
362 /* X11 requires these to longs and not ints */
364 unsigned long left_to_read;
365 unsigned char *val = (unsigned char *)0;
368 if (priv->xd == (Display *)0) {
372 tt_xatom = CALLX11(XInternAtom)(priv->xd, (char *)pname, False);
373 if (tt_xatom == None) {
376 CALLX11(XGetWindowProperty)(priv->xd, DefaultRootWindow(priv->xd),
378 0, 20, False, XA_STRING,
379 &anatom, &format, &items, &left_to_read,
381 if (val == (unsigned char *)0) {
385 CALLX11(XFree)((caddr_t)val);
391 // Parse a string in X11 "display" format and return the host and server
392 // number found. If parse errors occur return 0, else return 1 if the
393 // host is not the local host and 2 if the host is the local host. If the
394 // host is specified as "unix" which means use the local host with a Unix
395 // socket connection then return 3.
397 // XXX - the "hostname" paramater is an artifact of the fix for bug 1118012.
398 // if/when session IDs are re-worked to use only the process tree
399 // format internally, instead of the additional use of X session IDs,
400 // the parse_Xdisplay_string() function should be re-written to
404 parse_Xdisplay_string(_Tt_string display, _Tt_string &host, pid_t &svnum,_Tt_string &hostname)
412 offset = display.index(':');
419 (void)_tt_global->get_local_host(h);
420 host = h->stringaddr();
421 hostname = h->name();
424 // Get the hostid portion of an X display of the
427 host = display.mid(0, offset);
429 if (host == "unix") {
430 (void)_tt_global->get_local_host(h);
431 host = h->stringaddr();
432 hostname = h->name();
437 if (! _tt_global->find_host_byname(host, h)) {
438 if (! _tt_global->find_host(host, h, 1)) {
442 host = h->stringaddr();
443 hostname = h->name();
444 if (_tt_global->get_local_host(localh)) {
445 if (localh->stringaddr() == host) {
451 // now get the server number
452 dstr = (char *)display + offset + 1;
454 // ugh, a decnet connection
459 if (1 != sscanf(dstr, "%ld", &long_svnum)) {
460 svnum = (pid_t)long_svnum;
463 svnum = (pid_t)long_svnum;
471 // Returns a suitable name for this desktop session. Changing the value
472 // returned from this method should be done with care because it could
473 // compromise older versions of tooltalk clients/servers from
474 // communicating since a canonical name for a tooltalk desktop session
475 // contains the desktop session name in it and tooltalk session names
476 // indicate to clients how to contact the session.
478 _Tt_string _Tt_desktop::
479 session_name(_Tt_string dt_handle)
482 _Tt_string h, hostname;
484 _Tt_string name = (char *)0;
486 if (0==parse_Xdisplay_string(dt_handle, h, s, hostname)) {
489 sprintf(cid, "X %s %d", (char *)h, s);
500 _Tt_desktop_lock( const _Tt_desktop_ptr &dt )
503 if (! _dt.is_null()) {
511 if (! _dt.is_null()) {