Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[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 libraries 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   int len, bufferlen;
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   while (*stream != '\0')
262     stream++;
263   stream++;
264   locator = (char *) stream;
265
266   UAS_Pointer<UAS_Common> d;
267   mtry
268     {
269       if (strchr (locator, ':'))
270         {
271           d = UAS_Common::create(locator);
272         }
273       else
274         {
275           bufferlen = strlen("mmdb:LOCATOR=") + strlen(locator) + 1;
276           char *buffer = new char[bufferlen];
277           snprintf (buffer, bufferlen, "mmdb:LOCATOR=%s", locator);
278           d = UAS_Common::create (buffer);
279           if (d != (const int)0)
280             {
281               // (evil hack alert) 
282               g_scroll_to_locator = TRUE;
283               len = MIN(strlen(locator), 4096 - 1);
284               *((char *) memcpy(g_top_locator, locator, len) + len) = '\0';
285             }
286           delete [] buffer;
287         }
288     }
289   mcatch (demoException&, demo)
290     {
291       message_mgr().demo_failure(demo);
292     }
293   mcatch_any()
294     {
295       d = NULL;
296     }
297   end_try;
298
299   if (d != (const int)0)
300     {
301       d->retrieve();
302       reply_to_client(client, OLIAS_SUCCESS);
303     }
304   else
305     {
306       reply_to_client(client, OLIAS_LOCATOR_NOT_FOUND);
307       ON_DEBUG(cerr << "Document not found." << endl);
308     }
309 }
310
311
312 // /////////////////////////////////////////////////////////////////
313 // receive_olias_event
314 // /////////////////////////////////////////////////////////////////
315
316 void
317 ServiceMgr::receive_olias_event (Widget, XtPointer client_data,
318                                  Atom *selection, Atom * /* type */,
319                                  XtPointer value, unsigned long *length,
320                                  int * /* format */)
321 {
322   // NOTE: probably should verify type (olias_event_atom) and format 
323   Window client =
324     XGetSelectionOwner (window_system().display(),*selection);
325   ((ServiceMgr *) client_data)->
326     process_olias_event (client, (unsigned char *) value, *length);
327 }
328
329
330 // /////////////////////////////////////////////////////////////////
331 // reply_to_client
332 // /////////////////////////////////////////////////////////////////
333
334 void
335 ServiceMgr::reply_to_client (Window client, OliasStatus reply_code)
336 {
337   static XClientMessageEvent client_event;
338
339   // rtp - 19-Apr-95
340   //   Before we send a reply, we must determine if the client window
341   //   is an existing (valid) window. This is done below by searching
342   //   for it's window ID in the list of immediate children of the root
343   //   window. If the client window is no longer valid then we don't
344   //   send a reply. This method seems overly complex to me but after
345   //   consulting with our X gurus I determined that this is the best
346   //   (only?) way to accomplish this. This code fixes defect ID 16933.
347
348   //  rCs - 20Sept96
349   //  a better way might be to do an XSynch, install an error handler
350   //  try a X Command to see if an error is generated, do another,
351   //  XSynch, then restore the original Xlib error handler
352
353   Window        root, parent, *children;
354   unsigned int  i, nchildren;
355   Boolean       client_exists = False;
356
357   // Query root window for all of its immediate children.
358   if (XQueryTree(window_system().display(),
359                  DefaultRootWindow(window_system().display()),
360                  &root, &parent, &children, &nchildren)) {
361      // Search for the client window ID in root's list of children.
362      // Assumption: Window was created as a toplevel widget within
363      // external API client.
364      for (i = 0; i < nchildren; i++) {
365         if (children[i] == client) {
366            client_exists = True;
367            break;
368         }
369      }
370      // Free up the children array.
371      XFree(children);
372   }
373
374   // If not a valid window then punt sending the reply message
375   if (client == None || !client_exists)
376     return;
377
378   client_event.window = client;
379   client_event.type = ClientMessage;
380   client_event.message_type = _XA_OLIAS_REPLY;
381   client_event.format = 32;
382   client_event.data.l[0] = OLIAS_PROTOCOL_VERSION;
383   client_event.data.l[1] = reply_code;
384
385   ON_DEBUG(printf ("sending reply to 0x%lx\n", client));
386
387   XSendEvent (window_system().display(), client, False,
388               0L, (XEvent *) &client_event);
389   XFlush (window_system().display());
390 }
391
392
393 // /////////////////////////////////////////////////////////////////
394 // olias_send_event - internal version for olias-to-olias comm
395 // /////////////////////////////////////////////////////////////////
396
397 OliasStatus
398 olias_send_event (Widget, OliasEvent *event)
399 {
400   char *buffer = NULL;
401   char *locator;
402   int len, bufferlen;
403   UAS_Pointer<UAS_Common> d;
404
405   switch (event->type)
406     {
407       case OLIAS_NOOP_EVENT:
408         break;
409
410       case OLIAS_DISPLAY_EVENT:
411         locator = ((OliasDisplayEvent *) event)->locator;
412         ON_DEBUG (printf (">>> external-api display <%s>\n", locator));
413         mtry
414           {
415             if (strchr (locator, ':'))
416               {
417                 d = UAS_Common::create (locator);
418               }
419             else
420               {
421                 bufferlen = strlen("mmdb:LOCATOR=") + strlen(locator) + 1;
422                 buffer = new char[bufferlen];
423                 snprintf (buffer, bufferlen, "mmdb:LOCATOR=%s", locator);
424                 d = UAS_Common::create (buffer);
425                 delete [] buffer;
426                 if (d != (const int)0)
427                   {
428                     // (evil hack alert) 
429                     if (locator == NULL)
430                       return (OLIAS_TIMEOUT);
431                     ON_DEBUG(printf(">>> g_top_locator = %p\n", g_top_locator));
432                     if (g_top_locator[0] == '\0')
433                       return (OLIAS_TIMEOUT);
434                     g_scroll_to_locator = TRUE;
435                     len = MIN(strlen(locator), 4096 - 1);
436                     *((char *) memcpy(g_top_locator, locator, len) +len) = '\0';
437                   }
438               }
439           }
440         mcatch (demoException&, demo)
441           {
442             message_mgr().demo_failure(demo);
443           }
444         mcatch_any()
445           {
446             d = NULL;
447           }
448         end_try;
449         if (d != (const int)0)
450           {
451             d->retrieve();
452             return (OLIAS_SUCCESS);
453           }
454         else
455           {
456             message_mgr().info_dialog (
457                 (char*)UAS_String(CATGETS(Set_Messages, 46, "File a Bug")));
458             return (OLIAS_SUCCESS);
459             // return (OLIAS_LOCATOR_NOT_FOUND);   until help lib fixed
460           }
461         break;
462
463       default:
464         return (OLIAS_TIMEOUT);
465     }
466
467     return (OLIAS_LOCATOR_NOT_FOUND);
468 }