Mercurial > pidgin
annotate src/browser.c @ 1017:bbd0d51b7d14
[gaim-migrate @ 1027]
GAIM now responds to /version and /ping requests.
committer: Tailor Script <tailor@pidgin.im>
author | Rob Flynn <gaim@robflynn.com> |
---|---|
date | Sun, 22 Oct 2000 04:14:36 +0000 |
parents | 8f3bcde94e2c |
children | 56c7ceb986a8 |
rev | line source |
---|---|
1 | 1 /* |
2 * gaim | |
3 * | |
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
5 * | |
6 * some code: (most in this file) | |
7 * Copyright (C) 1996 Netscape Communications Corporation, all rights reserved. | |
8 * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 * | |
24 * This code is mainly taken from Netscape's sample implementation of | |
25 * their protocol. Nifty. | |
26 * | |
27 */ | |
28 | |
29 | |
349
b402a23f35df
[gaim-migrate @ 359]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
79
diff
changeset
|
30 #ifdef HAVE_CONFIG_H |
b402a23f35df
[gaim-migrate @ 359]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
79
diff
changeset
|
31 #include "../config.h" |
b402a23f35df
[gaim-migrate @ 359]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
79
diff
changeset
|
32 #endif |
1 | 33 #include <stdio.h> |
34 #include <stdlib.h> | |
35 #include <unistd.h> | |
36 #include <string.h> | |
37 | |
38 | |
39 | |
40 | |
41 #include <gtk/gtk.h> | |
42 #include <gdk/gdkprivate.h> | |
43 #include <gdk/gdkx.h> | |
44 #include "gaim.h" | |
45 | |
46 #ifndef _WIN32 | |
47 | |
48 | |
49 | |
50 | |
51 #include <X11/Xlib.h> | |
52 #include <X11/Xatom.h> | |
53 | |
54 | |
55 static const char *progname = "gaim"; | |
56 static const char *expected_mozilla_version = "1.1"; | |
57 | |
58 #define MOZILLA_VERSION_PROP "_MOZILLA_VERSION" | |
59 #define MOZILLA_LOCK_PROP "_MOZILLA_LOCK" | |
60 #define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND" | |
61 #define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE" | |
62 | |
63 static GdkAtom XA_MOZILLA_VERSION = 0; | |
64 static GdkAtom XA_MOZILLA_LOCK = 0; | |
65 static GdkAtom XA_MOZILLA_COMMAND = 0; | |
66 static GdkAtom XA_MOZILLA_RESPONSE = 0; | |
67 | |
68 | |
69 static int netscape_lock; | |
70 | |
71 | |
72 static Window | |
73 VirtualRootWindowOfScreen(screen) | |
74 Screen *screen; | |
75 { | |
76 static Screen *save_screen = (Screen *)0; | |
77 static Window root = (Window)0; | |
78 | |
79 if (screen != save_screen) { | |
80 Display *dpy = DisplayOfScreen(screen); | |
81 Atom __SWM_VROOT = None; | |
79 | 82 unsigned int i; |
1 | 83 Window rootReturn, parentReturn, *children; |
84 unsigned int numChildren; | |
85 | |
86 root = RootWindowOfScreen(screen); | |
87 | |
88 /* go look for a virtual root */ | |
89 __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); | |
90 if (XQueryTree(dpy, root, &rootReturn, &parentReturn, | |
91 &children, &numChildren)) { | |
92 for (i = 0; i < numChildren; i++) { | |
93 Atom actual_type; | |
94 int actual_format; | |
95 unsigned long nitems, bytesafter; | |
96 Window *newRoot = (Window *)0; | |
97 | |
98 if (XGetWindowProperty(dpy, children[i], | |
99 __SWM_VROOT, 0, 1, False, XA_WINDOW, | |
100 &actual_type, &actual_format, | |
101 &nitems, &bytesafter, | |
102 (unsigned char **) &newRoot) == Success | |
103 && newRoot) { | |
104 root = *newRoot; | |
105 break; | |
106 } | |
107 } | |
108 if (children) | |
109 XFree((char *)children); | |
110 } | |
111 | |
112 save_screen = screen; | |
113 } | |
114 | |
115 return root; | |
116 } | |
117 | |
118 /* The following code is Copyright (C) 1989 X Consortium */ | |
119 | |
120 static Window TryChildren(); | |
121 | |
122 /* Find a window with WM_STATE, else return win itself, as per ICCCM */ | |
123 | |
124 static Window GClientWindow (dpy, win) | |
125 Display *dpy; | |
126 Window win; | |
127 { | |
128 Atom WM_STATE; | |
129 Atom type = None; | |
130 int format; | |
131 unsigned long nitems, after; | |
132 unsigned char *data; | |
133 Window inf; | |
134 | |
135 WM_STATE = XInternAtom(dpy, "WM_STATE", True); | |
136 if (!WM_STATE) | |
137 return win; | |
138 XGetWindowProperty(dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, | |
139 &type, &format, &nitems, &after, &data); | |
140 if (type) | |
26 | 141 { |
142 XFree(data); | |
143 return win; | |
144 } | |
145 | |
1 | 146 inf = TryChildren(dpy, win, WM_STATE); |
147 if (!inf) | |
148 inf = win; | |
26 | 149 |
150 XFree(data); | |
151 | |
1 | 152 return inf; |
153 } | |
154 | |
155 static | |
156 Window TryChildren (dpy, win, WM_STATE) | |
157 Display *dpy; | |
158 Window win; | |
159 Atom WM_STATE; | |
160 { | |
161 Window root, parent; | |
162 Window *children; | |
163 unsigned int nchildren; | |
164 unsigned int i; | |
165 Atom type = None; | |
166 int format; | |
167 unsigned long nitems, after; | |
168 unsigned char *data; | |
169 Window inf = 0; | |
170 | |
171 if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) | |
172 return 0; | |
173 for (i = 0; !inf && (i < nchildren); i++) { | |
174 XGetWindowProperty(dpy, children[i], WM_STATE, 0, 0, False, | |
175 AnyPropertyType, &type, &format, &nitems, | |
176 &after, &data); | |
177 if (type) | |
178 inf = children[i]; | |
26 | 179 |
180 XFree(data); | |
1 | 181 } |
182 for (i = 0; !inf && (i < nchildren); i++) | |
183 inf = TryChildren(dpy, children[i], WM_STATE); | |
184 if (children) XFree((char *)children); | |
185 return inf; | |
186 } | |
187 | |
188 /* END X Consortium code */ | |
189 | |
190 | |
191 | |
192 static void mozilla_remote_init_atoms() | |
193 { | |
194 if (!XA_MOZILLA_VERSION) | |
195 XA_MOZILLA_VERSION = gdk_atom_intern(MOZILLA_VERSION_PROP, 0); | |
196 if (!XA_MOZILLA_LOCK) | |
197 XA_MOZILLA_LOCK = gdk_atom_intern(MOZILLA_LOCK_PROP, 0); | |
198 if (! XA_MOZILLA_COMMAND) | |
199 XA_MOZILLA_COMMAND = gdk_atom_intern(MOZILLA_COMMAND_PROP, 0); | |
200 if (! XA_MOZILLA_RESPONSE) | |
201 XA_MOZILLA_RESPONSE = gdk_atom_intern(MOZILLA_RESPONSE_PROP, 0); | |
202 } | |
203 | |
204 static GdkWindow *mozilla_remote_find_window() | |
205 { | |
206 int i; | |
207 Window root = VirtualRootWindowOfScreen(DefaultScreenOfDisplay(gdk_display)); | |
208 Window root2, parent, *kids; | |
209 unsigned int nkids; | |
210 Window result = 0; | |
211 Window tenative = 0; | |
212 unsigned char *tenative_version = 0; | |
213 | |
214 if (!XQueryTree (gdk_display, root, &root2, &parent, &kids, &nkids)) | |
215 { | |
216 sprintf (debug_buff, "%s: XQueryTree failed on display %s\n", progname, | |
217 DisplayString (gdk_display)); | |
218 debug_print(debug_buff); | |
219 return NULL; | |
220 } | |
221 | |
222 /* root != root2 is possible with virtual root WMs. */ | |
223 | |
224 if (!(kids && nkids)) { | |
225 sprintf (debug_buff, "%s: root window has no children on display %s\n", | |
226 progname, DisplayString (gdk_display)); | |
26 | 227 debug_print(debug_buff); |
1 | 228 return NULL; |
229 } | |
230 | |
231 for (i = nkids-1; i >= 0; i--) | |
232 { | |
233 Atom type; | |
234 int format; | |
235 unsigned long nitems, bytesafter; | |
236 unsigned char *version = 0; | |
237 Window w = GClientWindow (gdk_display, kids[i]); | |
238 int status = XGetWindowProperty (gdk_display, w, XA_MOZILLA_VERSION, | |
239 0, (65536 / sizeof (long)), | |
240 False, XA_STRING, | |
241 &type, &format, &nitems, &bytesafter, | |
242 &version); | |
26 | 243 |
1 | 244 if (! version) |
245 continue; | |
26 | 246 |
1 | 247 if (strcmp ((char *) version, expected_mozilla_version) && |
248 !tenative) | |
249 { | |
250 tenative = w; | |
251 tenative_version = version; | |
252 continue; | |
253 } | |
26 | 254 XFree(version); |
1 | 255 if (status == Success && type != None) |
256 { | |
257 result = w; | |
258 break; | |
259 } | |
260 } | |
261 | |
26 | 262 XFree(kids); |
263 | |
1 | 264 if (result && tenative) |
265 { | |
266 sprintf (debug_buff, | |
267 "%s: warning: both version %s (0x%x) and version\n" | |
268 "\t%s (0x%x) are running. Using version %s.\n", | |
269 progname, tenative_version, (unsigned int) tenative, | |
270 expected_mozilla_version, (unsigned int) result, | |
271 expected_mozilla_version); | |
272 debug_print(debug_buff); | |
26 | 273 XFree(tenative_version); |
1 | 274 return gdk_window_foreign_new(result); |
275 } | |
276 else if (tenative) | |
277 { | |
278 sprintf (debug_buff, | |
279 "%s: warning: expected version %s but found version\n" | |
280 "\t%s (0x%x) instead.\n", | |
281 progname, expected_mozilla_version, | |
282 tenative_version, (unsigned int) tenative); | |
283 debug_print(debug_buff); | |
26 | 284 XFree(tenative_version); |
1 | 285 return gdk_window_foreign_new(tenative); |
286 } | |
287 else if (result) | |
288 { | |
289 return gdk_window_foreign_new(result); | |
290 } | |
291 else | |
292 { | |
293 sprintf (debug_buff, "%s: not running on display %s\n", progname, | |
294 DisplayString (gdk_display)); | |
295 debug_print(debug_buff); | |
296 return NULL; | |
297 } | |
298 } | |
299 | |
300 | |
301 static char *lock_data = 0; | |
302 | |
303 static void mozilla_remote_obtain_lock (GdkWindow *window) | |
304 { | |
305 Bool locked = False; | |
306 | |
307 if (!lock_data) { | |
308 lock_data = (char *)g_malloc (255); | |
309 sprintf (lock_data, "pid%d@", getpid ()); | |
310 if (gethostname (lock_data + strlen (lock_data), 100)) { | |
311 return; | |
312 } | |
313 } | |
314 | |
315 do { | |
316 int result; | |
317 GdkAtom actual_type; | |
318 gint actual_format; | |
319 gint nitems; | |
320 unsigned char *data = 0; | |
321 | |
322 result = gdk_property_get (window, XA_MOZILLA_LOCK, | |
323 XA_STRING, 0, | |
324 (65536 / sizeof (long)), 0, | |
325 &actual_type, &actual_format, | |
326 &nitems, &data); | |
327 if (result != Success || actual_type == None) | |
328 { | |
329 /* It's not now locked - lock it. */ | |
330 sprintf (debug_buff, "%s: (writing " MOZILLA_LOCK_PROP | |
331 " \"%s\" to 0x%x)\n", | |
332 progname, lock_data, (unsigned int) window); | |
333 debug_print(debug_buff); | |
334 | |
335 gdk_property_change(window, XA_MOZILLA_LOCK, XA_STRING, | |
336 8, PropModeReplace, | |
337 (unsigned char *) lock_data, | |
338 strlen (lock_data)); | |
339 locked = True; | |
340 } | |
341 | |
342 if (!locked) { | |
343 /* Then just fuck it. */ | |
344 if (data) | |
345 g_free(data); | |
346 return; | |
347 } | |
348 if (data) | |
349 g_free(data); | |
350 } while (!locked); | |
351 } | |
352 | |
353 | |
354 static void mozilla_remote_free_lock (GdkWindow *window) | |
355 { | |
356 int result = 0; | |
357 GdkAtom actual_type; | |
358 gint actual_format; | |
359 gint nitems; | |
360 unsigned char *data = 0; | |
361 | |
362 sprintf (debug_buff, "%s: (deleting " MOZILLA_LOCK_PROP | |
363 " \"%s\" from 0x%x)\n", | |
364 progname, lock_data, (unsigned int) window); | |
365 debug_print(debug_buff); | |
366 | |
367 result = gdk_property_get(window, XA_MOZILLA_LOCK, XA_STRING, | |
368 0, (65536 / sizeof (long)), | |
369 1, &actual_type, &actual_format, | |
370 &nitems, &data); | |
371 if (result != Success) | |
372 { | |
373 sprintf (debug_buff, "%s: unable to read and delete " MOZILLA_LOCK_PROP | |
374 " property\n", | |
375 progname); | |
376 debug_print(debug_buff); | |
377 return; | |
378 } | |
379 else if (!data || !*data) | |
380 { | |
381 sprintf (debug_buff, "%s: invalid data on " MOZILLA_LOCK_PROP | |
382 " of window 0x%x.\n", | |
383 progname, (unsigned int) window); | |
384 debug_print(debug_buff); | |
385 return; | |
386 } | |
387 else if (strcmp ((char *) data, lock_data)) | |
388 { | |
389 sprintf (debug_buff, "%s: " MOZILLA_LOCK_PROP | |
390 " was stolen! Expected \"%s\", saw \"%s\"!\n", | |
391 progname, lock_data, data); | |
392 debug_print(debug_buff); | |
393 return; | |
394 } | |
395 | |
396 if (data) | |
397 g_free(data); | |
398 } | |
399 | |
400 | |
401 static int | |
402 mozilla_remote_command (GdkWindow *window, const char *command, | |
403 Bool raise_p) | |
404 { | |
405 int result = 0; | |
406 Bool done = False; | |
407 char *new_command = 0; | |
408 | |
409 /* The -noraise option is implemented by passing a "noraise" argument | |
410 to each command to which it should apply. | |
411 */ | |
412 if (!raise_p) | |
413 { | |
414 char *close; | |
79 | 415 new_command = g_malloc (strlen (command) + 20); |
1 | 416 strcpy (new_command, command); |
417 close = strrchr (new_command, ')'); | |
418 if (close) | |
419 strcpy (close, ", noraise)"); | |
420 else | |
421 strcat (new_command, "(noraise)"); | |
422 command = new_command; | |
423 } | |
424 | |
425 sprintf (debug_buff, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n", | |
426 progname, command, (unsigned int) window); | |
427 debug_print(debug_buff); | |
428 | |
429 gdk_property_change(window, XA_MOZILLA_COMMAND, XA_STRING, 8, | |
430 GDK_PROP_MODE_REPLACE, (unsigned char *) command, | |
431 strlen (command)); | |
432 | |
433 while (!done) { | |
434 GdkEvent *event; | |
435 | |
436 event = gdk_event_get(); | |
437 | |
438 if (!event) | |
439 continue; | |
440 | |
441 if (event->any.window != window) { | |
442 gtk_main_do_event(event); | |
443 continue; | |
444 } | |
445 | |
446 if (event->type == GDK_DESTROY && | |
447 event->any.window == window) { | |
448 | |
449 /* Print to warn user...*/ | |
450 sprintf (debug_buff, "%s: window 0x%x was destroyed.\n", | |
451 progname, (unsigned int) window); | |
452 debug_print(debug_buff); | |
453 result = 6; | |
454 goto DONE; | |
455 } else if (event->type == GDK_PROPERTY_NOTIFY && | |
456 event->property.state == GDK_PROPERTY_NEW_VALUE && | |
457 event->property.window == window && | |
458 event->property.atom == XA_MOZILLA_RESPONSE) { | |
459 GdkAtom actual_type; | |
460 gint actual_format, nitems; | |
461 unsigned char *data = 0; | |
462 | |
463 result = gdk_property_get (window, XA_MOZILLA_RESPONSE, | |
464 XA_STRING, 0, | |
465 (65536 / sizeof (long)), | |
466 1, | |
467 &actual_type, &actual_format, | |
468 &nitems, &data); | |
469 | |
470 | |
471 if (result == Success && data && *data) { | |
472 sprintf (debug_buff, "%s: (server sent " MOZILLA_RESPONSE_PROP | |
473 " \"%s\" to 0x%x.)\n", | |
474 progname, data, (unsigned int) window); | |
475 debug_print(debug_buff); | |
476 } | |
477 | |
478 if (result != Success) { | |
479 sprintf (debug_buff, "%s: failed reading " MOZILLA_RESPONSE_PROP | |
480 " from window 0x%0x.\n", | |
481 progname, (unsigned int) window); | |
482 debug_print(debug_buff); | |
483 result = 6; | |
484 done = True; | |
485 } else if (!data || strlen((char *) data) < 5) { | |
486 sprintf (debug_buff, "%s: invalid data on " MOZILLA_RESPONSE_PROP | |
487 " property of window 0x%0x.\n", | |
488 progname, (unsigned int) window); | |
489 debug_print(debug_buff); | |
490 result = 6; | |
491 done = True; | |
492 } else if (*data == '1') { /* positive preliminary reply */ | |
493 sprintf (debug_buff, "%s: %s\n", progname, data + 4); | |
494 debug_print(debug_buff); | |
495 /* keep going */ | |
496 done = False; | |
497 } else if (!strncmp ((char *)data, "200", 3)) { | |
498 result = 0; | |
499 done = True; | |
500 } else if (*data == '2') { | |
501 sprintf (debug_buff, "%s: %s\n", progname, data + 4); | |
502 debug_print(debug_buff); | |
503 result = 0; | |
504 done = True; | |
505 } else if (*data == '3') { | |
506 sprintf (debug_buff, "%s: internal error: " | |
507 "server wants more information? (%s)\n", | |
508 progname, data); | |
509 debug_print(debug_buff); | |
510 result = 3; | |
511 done = True; | |
512 } else if (*data == '4' || *data == '5') { | |
513 sprintf (debug_buff, "%s: %s\n", progname, data + 4); | |
514 debug_print(debug_buff); | |
515 result = (*data - '0'); | |
516 done = True; | |
517 } else { | |
518 sprintf (debug_buff, | |
519 "%s: unrecognised " MOZILLA_RESPONSE_PROP | |
520 " from window 0x%x: %s\n", | |
521 progname, (unsigned int) window, data); | |
522 debug_print(debug_buff); | |
523 result = 6; | |
524 done = True; | |
525 } | |
526 | |
527 if (data) | |
528 g_free(data); | |
529 } | |
530 else if (event->type == GDK_PROPERTY_NOTIFY && | |
531 event->property.window == window && | |
532 event->property.state == GDK_PROPERTY_DELETE && | |
533 event->property.atom == XA_MOZILLA_COMMAND) { | |
534 sprintf (debug_buff, "%s: (server 0x%x has accepted " | |
535 MOZILLA_COMMAND_PROP ".)\n", | |
536 progname, (unsigned int) window); | |
537 debug_print(debug_buff); | |
538 } | |
539 gdk_event_free(event); | |
540 } | |
541 | |
542 DONE: | |
543 | |
544 if (new_command) | |
545 g_free (new_command); | |
546 | |
547 return result; | |
548 } | |
549 | |
550 | |
551 gint check_netscape(char *msg) | |
552 { | |
553 int status; | |
554 GdkWindow *window; | |
555 | |
556 mozilla_remote_init_atoms (); | |
557 window = mozilla_remote_find_window(); | |
558 | |
559 if (window) { | |
560 | |
561 XSelectInput(gdk_display, ((GdkWindowPrivate *)window)->xwindow, | |
562 (PropertyChangeMask|StructureNotifyMask)); | |
563 | |
564 | |
565 mozilla_remote_obtain_lock(window); | |
566 | |
567 status = mozilla_remote_command(window, msg, False); | |
568 | |
569 if (status != 6) | |
570 mozilla_remote_free_lock(window); | |
571 | |
572 gtk_timeout_add(1000, (GtkFunction)clean_pid, NULL); | |
573 | |
574 netscape_lock = 0; | |
575 | |
576 g_free(msg); | |
577 return FALSE; | |
578 } else | |
579 return TRUE; | |
580 } | |
581 | |
582 | |
583 static void netscape_command(char *command) | |
584 { | |
585 int status; | |
586 pid_t pid; | |
587 GdkWindow *window; | |
588 | |
589 if (netscape_lock) | |
590 return; | |
591 | |
592 netscape_lock = 1; | |
593 | |
594 | |
595 | |
596 mozilla_remote_init_atoms(); | |
597 window = mozilla_remote_find_window(); | |
598 | |
599 if (window) { | |
600 | |
601 XSelectInput(gdk_display, ((GdkWindowPrivate *)window)->xwindow, | |
602 (PropertyChangeMask|StructureNotifyMask)); | |
603 | |
604 mozilla_remote_obtain_lock(window); | |
605 | |
606 status = mozilla_remote_command(window, command, False); | |
607 | |
608 if (status != 6) | |
609 mozilla_remote_free_lock(window); | |
610 | |
611 netscape_lock = 0; | |
612 | |
26 | 613 gdk_window_destroy (window); |
1 | 614 } else { |
615 pid = fork(); | |
616 if (pid == 0) { | |
617 char *args[2]; | |
618 int e; | |
619 | |
620 args[0] = g_strdup("netscape"); | |
621 args[1] = NULL; | |
622 e = execvp(args[0], args); | |
79 | 623 printf("Hello%d\n", getppid()); |
1 | 624 |
625 _exit(0); | |
626 } else { | |
627 char *tmp = g_strdup(command); | |
628 gtk_timeout_add(200, (GtkFunction)check_netscape, tmp); | |
629 } | |
630 } | |
631 | |
632 } | |
633 | |
634 void open_url(GtkWidget *w, char *url) { | |
733 | 635 |
1 | 636 if (web_browser == BROWSER_NETSCAPE) { |
637 char *command = g_malloc(1024); | |
638 | |
639 g_snprintf(command, 1024, "OpenURL(%s)", url); | |
640 | |
641 netscape_command(command); | |
642 g_free(command); | |
643 } else if (web_browser == BROWSER_KFM) { | |
644 pid_t pid; | |
645 | |
646 pid = fork(); | |
647 | |
648 if (pid == 0) { | |
649 char *args[4]; | |
650 | |
651 args[0] = g_strdup("kfmclient"); | |
652 args[1] = g_strdup("openURL"); | |
653 args[2] = url;; | |
654 args[3] = NULL; | |
655 | |
656 execvp(args[0], args); | |
657 _exit(0); | |
658 } else { | |
659 gtk_timeout_add(1000, (GtkFunction)clean_pid, NULL); | |
660 } | |
733 | 661 #ifdef USE_GNOME |
662 } else if (web_browser == BROWSER_GNOME) { | |
663 gnome_url_show(url); | |
664 #endif /* USE_GNOME */ | |
1 | 665 } else if (web_browser == BROWSER_MANUAL) { |
666 pid_t pid; | |
667 | |
668 pid = fork(); | |
669 | |
670 if (pid == 0) { | |
671 char *args[4]; | |
672 | |
673 char command[1024]; | |
674 | |
675 g_snprintf(command, sizeof(command), web_command, url); | |
676 | |
677 args[0] = "sh"; | |
678 args[1] = "-c"; | |
679 args[2] = command; | |
680 args[3] = NULL; | |
681 | |
682 execvp(args[0], args); | |
683 | |
684 _exit(0); | |
685 } else { | |
686 gtk_timeout_add(1000, (GtkFunction)clean_pid, NULL); | |
687 } | |
688 } else if (web_browser == BROWSER_INTERNAL) { | |
689 g_show_info(url); | |
690 } | |
691 } | |
692 | |
693 void add_bookmark(GtkWidget *w, char *url) { | |
694 if (web_browser == BROWSER_NETSCAPE) { | |
695 char *command = g_malloc(1024); | |
696 | |
697 g_snprintf(command, 1024, "AddBookmark(%s)", url); | |
698 | |
699 netscape_command(command); | |
700 g_free(command); | |
701 } | |
702 } | |
703 | |
704 void open_url_nw(GtkWidget *w, char *url) { | |
705 if (web_browser == BROWSER_NETSCAPE) { | |
706 char *command = g_malloc(1024); | |
707 | |
708 g_snprintf(command, 1024, "OpenURL(%s, new-window)", url); | |
709 | |
710 netscape_command(command); | |
711 g_free(command); | |
733 | 712 } else { |
713 open_url(w, url); | |
1 | 714 } |
715 } | |
716 | |
717 #else | |
718 | |
719 /* Sooner or later, I shall support Windows clicking! */ | |
720 | |
721 void add_bookmark(GtkWidget *w, char *url) { } | |
722 void open_url_nw(GtkWidget *w, char *url) { } | |
723 void open_url(GtkWidget *w, char *url) { } | |
724 | |
725 | |
726 #endif _WIN32 |