dtinfo subtree dtinfo
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Managers / ServiceMgrX.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 /*
24  * $TOG: ServiceMgrX.C /main/12 1997/06/18 17:32:19 samborn $
25  *
26  * Copyright (c) 1992 HaL Computer Systems, Inc.  All rights reserved.
27  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28  * States.  Use of a copyright notice is precautionary only and does not
29  * imply publication or disclosure.
30  * 
31  * This software contains confidential information and trade secrets of HaL
32  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
33  * without the prior express written permission of HaL Computer Systems, Inc.
34  * 
35  *                         RESTRICTED RIGHTS LEGEND
36  * Use, duplication, or disclosure by the Government is subject to
37  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38  * Technical Data and Computer Software clause at DFARS 252.227-7013.
39  *                        HaL Computer Systems, Inc.
40  *                  1315 Dell Avenue, Campbell, CA  95008
41  * 
42  */
43
44 #include "UAS.hh"
45
46 #define L_Agents
47
48 #define C_ServiceMgr
49 #define C_NodeMgr
50 #define C_ClientEventMgr
51 #define C_MessageMgr
52 #define L_Managers
53
54 #define C_WindowSystem
55 #define L_Other
56
57 #include "Prelude.h"
58
59 #include "Managers/CatMgr.hh"
60 #include "Registration.hh"
61
62 #include <string.h>
63
64 #include "external-api/olias.h"
65 #include "utility/mmdb_exception.h"
66
67 LONG_LIVED_CC(ServiceMgr,service_manager)
68
69 #define OLIAS_PROTOCOL_VERSION  1
70
71 #define OLIAS_WINDOW_ID_ATOM    "__OLIAS_WINDOW_ID"
72 #define OLIAS_EVENT_ATOM        "__OLIAS_EVENT"
73 #define OLIAS_REPLY_ATOM        "__OLIAS_REPLY"
74
75 Atom _XA_OLIAS_WINDOW_ID;
76 Atom _XA_OLIAS_EVENT;
77 Atom _XA_OLIAS_REPLY;
78
79 extern bool g_scroll_to_locator;
80 extern char g_top_locator[];
81
82 // /////////////////////////////////////////////////////////////////
83 // class constructor
84 // /////////////////////////////////////////////////////////////////
85
86 ServiceMgr::ServiceMgr()
87 {
88 #if 0
89   // We need to wait for the window to be mapped before doing anything
90   XtAddEventHandler (window_system().toplevel(), StructureNotifyMask, False,
91                      (XtEventHandler) handle_toplevel_mapped, this);
92 #endif
93 }
94
95
96 // /////////////////////////////////////////////////////////////////
97 // class destructor
98 // /////////////////////////////////////////////////////////////////
99
100 ServiceMgr::~ServiceMgr()
101 {
102   // Need to stop being the OLIAS server if it's us.
103
104   //  XGrabServer (window_system().display());
105
106   Window current_server =
107     XGetSelectionOwner (window_system().display(), _XA_OLIAS_WINDOW_ID);
108
109   ON_DEBUG(printf ("Current OLIAS server is window 0x%lx\n", current_server));
110   if (current_server == XtWindow (window_system().toplevel()))
111     {
112       ON_DEBUG(printf ("Done being the OLIAS server...\n"));
113       ON_DEBUG(fflush (stdout));
114
115       // OK to use CurrentTime because there is no chance of contention.
116       XSetSelectionOwner (window_system().display(), _XA_OLIAS_WINDOW_ID,
117                           None, CurrentTime);
118     }
119       
120   //  XUngrabServer (window_system().display());
121 }
122
123 // /////////////////////////////////////////////////////////////////
124 // create_atoms
125 // /////////////////////////////////////////////////////////////////
126
127 void
128 ServiceMgr::create_atoms()
129 {
130   static Boolean created = False;
131
132   if (!created)
133     {
134       enum { XA_OLIAS_WINDOW_ID_ATOM, XA_OLIAS_EVENT_ATOM,
135              XA_OLIAS_REPLY_ATOM, NUM_ATOMS }; 
136       static const char *atom_names[] = { OLIAS_WINDOW_ID_ATOM,
137              OLIAS_EVENT_ATOM, OLIAS_REPLY_ATOM };
138
139       Atom atoms[XtNumber(atom_names)];
140
141       XInternAtoms (window_system().display(), (char**)atom_names,
142                     XtNumber((char**)atom_names), False, atoms);
143
144       _XA_OLIAS_WINDOW_ID = atoms[XA_OLIAS_WINDOW_ID_ATOM];
145       _XA_OLIAS_EVENT = atoms[XA_OLIAS_EVENT_ATOM];
146       _XA_OLIAS_REPLY = atoms[XA_OLIAS_REPLY_ATOM];
147
148       created = True;
149     }
150 }
151
152 // /////////////////////////////////////////////////////////////////
153 // establish_server - see if there's a server, become one if not
154 // /////////////////////////////////////////////////////////////////
155
156 void
157 ServiceMgr::establish_server()
158 {
159   create_atoms();
160
161   // Operations in this routine must be atomic to avoid race conditions,
162   // hence the server grab.
163
164   XGrabServer (window_system().display());
165
166   Window current_server =
167     XGetSelectionOwner (window_system().display(), _XA_OLIAS_WINDOW_ID);
168
169   ON_DEBUG(printf ("Current OLIAS server is window 0x%lx\n", current_server));
170
171   // If no current server, we'll become the server.
172   if (current_server == None)
173     {
174       ON_DEBUG(printf ("Attempting to become OLIAS server..."));
175       ON_DEBUG(fflush (stdout));
176       current_server = XtWindow (window_system().toplevel());
177
178       // OK to use CurrentTime because there is no chance of contention.
179       XSetSelectionOwner (window_system().display(), _XA_OLIAS_WINDOW_ID,
180                           current_server, CurrentTime);
181
182       // Make sure it worked.
183       current_server = XGetSelectionOwner (window_system().display(),
184                                            _XA_OLIAS_WINDOW_ID);
185
186       if (current_server == XtWindow (window_system().toplevel()))
187         {
188           client_event_manager().register_handler(this, window_system().toplevel());
189           ON_DEBUG(puts ("successful!"));
190         }
191       else
192         {
193           ON_DEBUG(puts ("failed!"));
194         }
195     }
196
197   XUngrabServer (window_system().display());
198 }
199
200 // /////////////////////////////////////////////////////////////////
201 // get_olias_event
202 // /////////////////////////////////////////////////////////////////
203
204 void
205 ServiceMgr::get_olias_event (XEvent *event)
206 {
207   // Make sure it's the right event first. 
208   if (event->type != ClientMessage ||
209       event->xclient.message_type != _XA_OLIAS_EVENT)
210     return;
211
212   Atom selection = event->xclient.data.l[2];
213   Time time      = event->xclient.data.l[3];
214
215   /* -------- Ask for the client the event from the client. -------- */
216   ON_DEBUG(puts ("OLIAS: Received a client display event!"));
217
218   XtGetSelectionValue (window_system().toplevel(), selection,
219                        _XA_OLIAS_EVENT,
220                        (XtSelectionCallbackProc) receive_olias_event,
221                        this, time);                    
222 }
223
224
225 // /////////////////////////////////////////////////////////////////
226 // handle_event - dispatch handle application request
227 // /////////////////////////////////////////////////////////////////
228
229 void
230 ServiceMgr::handle_event(Widget, XEvent *event, Boolean *)
231 {
232   get_olias_event(event);
233 }
234
235 // /////////////////////////////////////////////////////////////////
236 // process_olias_event
237 // /////////////////////////////////////////////////////////////////
238
239 void
240 ServiceMgr::process_olias_event (Window client,
241                                  unsigned char *stream, unsigned long)
242 {
243   /* Return immediately if the selection couldn't be converted. */
244   if (stream == NULL)
245     return;
246
247   unsigned char event_type = *stream++;
248   char *infobase;
249   char *locator;                // NOTE: make fixed width and add "mmdb:" to
250                                 // front ? Should eventually go into calling
251                                 // program to determine doc type.
252
253   if (event_type != 1)
254     {
255       ON_DEBUG(fprintf (stderr, "received unknown event"));
256       return;
257     }
258
259   // Skip over the defunct infobase name.
260   // NOTE:  It should be removed from the olias api.  DJB 
261   infobase = (char *) stream;
262   while (*stream != '\0')
263     stream++;
264   stream++;
265   locator = (char *) stream;
266
267   UAS_Pointer<UAS_Common> d;
268   mtry
269     {
270       if (strchr (locator, ':'))
271         {
272           d = UAS_Common::create(locator);
273         }
274       else
275         {
276           char *buffer = new char[strlen("mmdb:LOCATOR=") + strlen(locator) + 1];
277           sprintf (buffer, "mmdb:LOCATOR=%s", locator);
278           d = UAS_Common::create (buffer);
279           if (d != (const int)NULL)
280             {
281               // (evil hack alert) 
282               g_scroll_to_locator = TRUE;
283               strcpy (g_top_locator, locator);
284             }
285           delete [] buffer;
286         }
287     }
288   mcatch (demoException&, demo)
289     {
290       message_mgr().demo_failure(demo);
291     }
292   mcatch_any()
293     {
294       d = NULL;
295     }
296   end_try;
297
298   if (d != (const int)NULL)
299     {
300       d->retrieve();
301       reply_to_client(client, OLIAS_SUCCESS);
302     }
303   else
304     {
305       reply_to_client(client, OLIAS_LOCATOR_NOT_FOUND);
306       ON_DEBUG(cerr << "Document not found." << endl);
307     }
308 }
309
310
311 // /////////////////////////////////////////////////////////////////
312 // receive_olias_event
313 // /////////////////////////////////////////////////////////////////
314
315 void
316 ServiceMgr::receive_olias_event (Widget, XtPointer client_data,
317                                  Atom *selection, Atom * /* type */,
318                                  XtPointer value, unsigned long *length,
319                                  int * /* format */)
320 {
321   // NOTE: probably should verify type (olias_event_atom) and format 
322   Window client =
323     XGetSelectionOwner (window_system().display(),*selection);
324   ((ServiceMgr *) client_data)->
325     process_olias_event (client, (unsigned char *) value, *length);
326 }
327
328
329 // /////////////////////////////////////////////////////////////////
330 // reply_to_client
331 // /////////////////////////////////////////////////////////////////
332
333 void
334 ServiceMgr::reply_to_client (Window client, OliasStatus reply_code)
335 {
336   static XClientMessageEvent client_event;
337
338   // rtp - 19-Apr-95
339   //   Before we send a reply, we must determine if the client window
340   //   is an existing (valid) window. This is done below by searching
341   //   for it's window ID in the list of immediate children of the root
342   //   window. If the client window is no longer valid then we don't
343   //   send a reply. This method seems overly complex to me but after
344   //   consulting with our X gurus I determined that this is the best
345   //   (only?) way to accomplish this. This code fixes defect ID 16933.
346
347   //  rCs - 20Sept96
348   //  a better way might be to do an XSynch, install an error handler
349   //  try a X Command to see if an error is generated, do another,
350   //  XSynch, then restore the original Xlib error handler
351
352   Window        root, parent, *children;
353   unsigned int  i, nchildren;
354   Boolean       client_exists = False;
355
356   // Query root window for all of its immediate children.
357   if (XQueryTree(window_system().display(),
358                  DefaultRootWindow(window_system().display()),
359                  &root, &parent, &children, &nchildren)) {
360      // Search for the client window ID in root's list of children.
361      // Assumption: Window was created as a toplevel widget within
362      // external API client.
363      for (i = 0; i < nchildren; i++) {
364         if (children[i] == client) {
365            client_exists = True;
366            break;
367         }
368      }
369      // Free up the children array.
370      XFree(children);
371   }
372
373   // If not a valid window then punt sending the reply message
374   if (client == None || !client_exists)
375     return;
376
377   client_event.window = client;
378   client_event.type = ClientMessage;
379   client_event.message_type = _XA_OLIAS_REPLY;
380   client_event.format = 32;
381   client_event.data.l[0] = OLIAS_PROTOCOL_VERSION;
382   client_event.data.l[1] = reply_code;
383
384   ON_DEBUG(printf ("sending reply to 0x%lx\n", client));
385
386   XSendEvent (window_system().display(), client, False,
387               0L, (XEvent *) &client_event);
388   XFlush (window_system().display());
389 }
390
391
392 // /////////////////////////////////////////////////////////////////
393 // olias_send_event - internal version for olias-to-olias comm
394 // /////////////////////////////////////////////////////////////////
395
396 OliasStatus
397 olias_send_event (Widget, OliasEvent *event)
398 {
399   char *buffer = NULL;
400   char *locator;
401   UAS_Pointer<UAS_Common> d;
402
403   switch (event->type)
404     {
405       case OLIAS_NOOP_EVENT:
406         break;
407
408       case OLIAS_DISPLAY_EVENT:
409         locator = ((OliasDisplayEvent *) event)->locator;
410         ON_DEBUG (printf (">>> external-api display <%s>\n", locator));
411         mtry
412           {
413             if (strchr (locator, ':'))
414               {
415                 d = UAS_Common::create (locator);
416               }
417             else
418               {
419                 buffer = new char[strlen("mmdb:LOCATOR=") + strlen(locator) + 1];
420                 sprintf (buffer, "mmdb:LOCATOR=%s", locator);
421                 d = UAS_Common::create (buffer);
422                 delete [] buffer;
423                 if (d != (const int)NULL)
424                   {
425                     // (evil hack alert) 
426                     if (locator == NULL)
427                       return (OLIAS_TIMEOUT);
428                     ON_DEBUG (printf (">>> g_top_locator = %p\n", g_top_locator));
429                     if (g_top_locator == NULL)
430                       return (OLIAS_TIMEOUT);
431                     g_scroll_to_locator = TRUE;
432                     strcpy (g_top_locator, locator);
433                   }
434               }
435           }
436         mcatch (demoException&, demo)
437           {
438             message_mgr().demo_failure(demo);
439           }
440         mcatch_any()
441           {
442             d = NULL;
443           }
444         end_try;
445         if (d != (const int)NULL)
446           {
447             d->retrieve();
448             return (OLIAS_SUCCESS);
449           }
450         else
451           {
452             message_mgr().info_dialog (
453                 (char*)UAS_String(CATGETS(Set_Messages, 46, "File a Bug")));
454             return (OLIAS_SUCCESS);
455             // return (OLIAS_LOCATOR_NOT_FOUND);   until help lib fixed
456           }
457         break;
458
459       default:
460         return (OLIAS_TIMEOUT);
461     }
462 }