diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llappviewerlinux.cpp | 307 |
1 files changed, 270 insertions, 37 deletions
diff --git a/linden/indra/newview/llappviewerlinux.cpp b/linden/indra/newview/llappviewerlinux.cpp index 0a4a9cf..643013b 100644 --- a/linden/indra/newview/llappviewerlinux.cpp +++ b/linden/indra/newview/llappviewerlinux.cpp | |||
@@ -1,6 +1,6 @@ | |||
1 | /** | 1 | /** |
2 | * @file llappviewerlinux.cpp | 2 | * @file llappviewerlinux.cpp |
3 | * @brief The LLAppViewerWin32 class definitions | 3 | * @brief The LLAppViewerLinux class definitions |
4 | * | 4 | * |
5 | * $LicenseInfo:firstyear=2007&license=viewergpl$ | 5 | * $LicenseInfo:firstyear=2007&license=viewergpl$ |
6 | * | 6 | * |
@@ -36,8 +36,10 @@ | |||
36 | #include "llcommandlineparser.h" | 36 | #include "llcommandlineparser.h" |
37 | 37 | ||
38 | #include "llmemtype.h" | 38 | #include "llmemtype.h" |
39 | #include "llurldispatcher.h" // SLURL from other app instance | ||
39 | #include "llviewernetwork.h" | 40 | #include "llviewernetwork.h" |
40 | #include "llviewercontrol.h" | 41 | #include "llviewercontrol.h" |
42 | #include "llwindowsdl.h" | ||
41 | #include "llmd5.h" | 43 | #include "llmd5.h" |
42 | #include "llfindlocale.h" | 44 | #include "llfindlocale.h" |
43 | 45 | ||
@@ -60,6 +62,17 @@ | |||
60 | # include "ELFIO/ELFIO.h" // for better backtraces | 62 | # include "ELFIO/ELFIO.h" // for better backtraces |
61 | #endif | 63 | #endif |
62 | 64 | ||
65 | #if LL_DBUS_ENABLED | ||
66 | # include "llappviewerlinux_api_dbus.h" | ||
67 | |||
68 | // regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h: | ||
69 | #define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) | ||
70 | #undef g_return_if_fail | ||
71 | #define g_return_if_fail(COND) llg_return_if_fail(COND) | ||
72 | // The generated API | ||
73 | # include "llappviewerlinux_api.h" | ||
74 | #endif | ||
75 | |||
63 | namespace | 76 | namespace |
64 | { | 77 | { |
65 | int gArgC = 0; | 78 | int gArgC = 0; |
@@ -321,6 +334,193 @@ bool LLAppViewerLinux::init() | |||
321 | return LLAppViewer::init(); | 334 | return LLAppViewer::init(); |
322 | } | 335 | } |
323 | 336 | ||
337 | bool LLAppViewerLinux::restoreErrorTrap() | ||
338 | { | ||
339 | // *NOTE:Mani there is a case for implementing this or the mac. | ||
340 | // Linux doesn't need it to my knowledge. | ||
341 | return true; | ||
342 | } | ||
343 | |||
344 | ///////////////////////////////////////// | ||
345 | #if LL_DBUS_ENABLED | ||
346 | |||
347 | typedef struct | ||
348 | { | ||
349 | GObjectClass parent_class; | ||
350 | } ViewerAppAPIClass; | ||
351 | |||
352 | static void viewerappapi_init(ViewerAppAPI *server); | ||
353 | static void viewerappapi_class_init(ViewerAppAPIClass *klass); | ||
354 | |||
355 | /// | ||
356 | |||
357 | // regrettable hacks to give us better runtime compatibility with older systems in general | ||
358 | static GType llg_type_register_static_simple_ONCE(GType parent_type, | ||
359 | const gchar *type_name, | ||
360 | guint class_size, | ||
361 | GClassInitFunc class_init, | ||
362 | guint instance_size, | ||
363 | GInstanceInitFunc instance_init, | ||
364 | GTypeFlags flags) | ||
365 | { | ||
366 | static GTypeInfo type_info; | ||
367 | memset(&type_info, 0, sizeof(type_info)); | ||
368 | |||
369 | type_info.class_size = class_size; | ||
370 | type_info.class_init = class_init; | ||
371 | type_info.instance_size = instance_size; | ||
372 | type_info.instance_init = instance_init; | ||
373 | |||
374 | return g_type_register_static(parent_type, type_name, &type_info, flags); | ||
375 | } | ||
376 | #define llg_intern_static_string(S) (S) | ||
377 | #define g_intern_static_string(S) llg_intern_static_string(S) | ||
378 | #define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) | ||
379 | |||
380 | G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT); | ||
381 | |||
382 | void viewerappapi_class_init(ViewerAppAPIClass *klass) | ||
383 | { | ||
384 | } | ||
385 | |||
386 | static bool dbus_server_init = false; | ||
387 | |||
388 | void viewerappapi_init(ViewerAppAPI *server) | ||
389 | { | ||
390 | // Connect to the default DBUS, register our service/API. | ||
391 | |||
392 | if (!dbus_server_init) | ||
393 | { | ||
394 | GError *error = NULL; | ||
395 | |||
396 | server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error); | ||
397 | if (server->connection) | ||
398 | { | ||
399 | lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info); | ||
400 | |||
401 | lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server)); | ||
402 | |||
403 | DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); | ||
404 | |||
405 | guint request_name_ret_unused; | ||
406 | // akin to org_freedesktop_DBus_request_name | ||
407 | if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID)) | ||
408 | { | ||
409 | // total success. | ||
410 | dbus_server_init = true; | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | llwarns << "Unable to register service name: " << error->message << llendl; | ||
415 | } | ||
416 | |||
417 | g_object_unref(serverproxy); | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | g_warning("Unable to connect to dbus: %s", error->message); | ||
422 | } | ||
423 | |||
424 | if (error) | ||
425 | g_error_free(error); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error) | ||
430 | { | ||
431 | bool success = false; | ||
432 | |||
433 | llinfos << "Was asked to go to slurl: " << slurl << llendl; | ||
434 | |||
435 | const bool from_external_browser = true; | ||
436 | if (LLURLDispatcher::dispatch(slurl, from_external_browser)) | ||
437 | { | ||
438 | // bring window to foreground, as it has just been "launched" from a URL | ||
439 | // todo: hmm, how to get there from here? | ||
440 | //xxx->mWindow->bringToFront(); | ||
441 | success = true; | ||
442 | } | ||
443 | |||
444 | *success_rtn = g_new (gboolean, 1); | ||
445 | (*success_rtn)[0] = (gboolean)success; | ||
446 | |||
447 | return TRUE; // the invokation succeeded, even if the actual dispatch didn't. | ||
448 | } | ||
449 | |||
450 | /// | ||
451 | |||
452 | //virtual | ||
453 | bool LLAppViewerLinux::initSLURLHandler() | ||
454 | { | ||
455 | if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) | ||
456 | { | ||
457 | return false; // failed | ||
458 | } | ||
459 | |||
460 | g_type_init(); | ||
461 | |||
462 | //ViewerAppAPI *api_server = (ViewerAppAPI*) | ||
463 | g_object_new(viewerappapi_get_type(), NULL); | ||
464 | |||
465 | return true; | ||
466 | } | ||
467 | |||
468 | //virtual | ||
469 | bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) | ||
470 | { | ||
471 | if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) | ||
472 | { | ||
473 | return false; // failed | ||
474 | } | ||
475 | |||
476 | bool success = false; | ||
477 | DBusGConnection *bus; | ||
478 | GError *error = NULL; | ||
479 | |||
480 | g_type_init(); | ||
481 | |||
482 | bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); | ||
483 | if (bus) | ||
484 | { | ||
485 | gboolean rtn = FALSE; | ||
486 | DBusGProxy *remote_object = | ||
487 | lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE); | ||
488 | |||
489 | if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error, | ||
490 | G_TYPE_STRING, url.c_str(), G_TYPE_INVALID, | ||
491 | G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID)) | ||
492 | { | ||
493 | success = rtn; | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | llinfos << "Call-out to other instance failed (perhaps not running): " << error->message << llendl; | ||
498 | } | ||
499 | |||
500 | g_object_unref(G_OBJECT(remote_object)); | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | llwarns << "Couldn't connect to session bus: " << error->message << llendl; | ||
505 | } | ||
506 | |||
507 | if (error) | ||
508 | g_error_free(error); | ||
509 | |||
510 | return success; | ||
511 | } | ||
512 | |||
513 | #else // LL_DBUS_ENABLED | ||
514 | bool LLAppViewerLinux::initSLURLHandler() | ||
515 | { | ||
516 | return false; // not implemented without dbus | ||
517 | } | ||
518 | bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) | ||
519 | { | ||
520 | return false; // not implemented without dbus | ||
521 | } | ||
522 | #endif // LL_DBUS_ENABLED | ||
523 | |||
324 | void LLAppViewerLinux::handleSyncCrashTrace() | 524 | void LLAppViewerLinux::handleSyncCrashTrace() |
325 | { | 525 | { |
326 | // This backtrace writes into stack_trace.log | 526 | // This backtrace writes into stack_trace.log |
@@ -331,57 +531,90 @@ void LLAppViewerLinux::handleSyncCrashTrace() | |||
331 | # endif // LL_ELFBIN | 531 | # endif // LL_ELFBIN |
332 | } | 532 | } |
333 | 533 | ||
334 | void LLAppViewerLinux::handleCrashReporting() | 534 | void LLAppViewerLinux::handleCrashReporting(bool reportFreeze) |
335 | { | 535 | { |
336 | const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); | 536 | std::string cmd =gDirUtilp->getAppRODataDir(); |
337 | 537 | cmd += gDirUtilp->getDirDelimiter(); | |
338 | // Always generate the report, have the logger do the asking, and | 538 | #if LL_LINUX |
339 | // don't wait for the logger before exiting (-> total cleanup). | 539 | cmd += "linux-crash-logger.bin"; |
340 | if (CRASH_BEHAVIOR_NEVER_SEND != cb) | 540 | #else // LL_SOLARIS |
341 | { | 541 | cmd += "bin/solaris-crash-logger"; |
342 | // launch the actual crash logger | 542 | #endif // LL_LINUX |
343 | const char* ask_dialog = "-dialog"; | 543 | |
344 | if (CRASH_BEHAVIOR_ASK != cb) | 544 | if(reportFreeze) |
345 | ask_dialog = ""; // omit '-dialog' option | 545 | { |
346 | std::string cmd =gDirUtilp->getAppRODataDir(); | 546 | char* const cmdargv[] = |
347 | cmd += gDirUtilp->getDirDelimiter(); | 547 | {(char*)cmd.c_str(), |
348 | cmd += "linux-crash-logger.bin"; | 548 | (char*)"-previous", |
349 | const char * cmdargv[] = | ||
350 | {cmd.c_str(), | ||
351 | ask_dialog, | ||
352 | "-user", | ||
353 | (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(), | ||
354 | "-name", | ||
355 | LLAppViewer::instance()->getSecondLifeTitle().c_str(), | ||
356 | NULL}; | 549 | NULL}; |
357 | fflush(NULL); | 550 | |
551 | fflush(NULL); // flush all buffers before the child inherits them | ||
358 | pid_t pid = fork(); | 552 | pid_t pid = fork(); |
359 | if (pid == 0) | 553 | if (pid == 0) |
360 | { // child | 554 | { // child |
361 | execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */ | 555 | execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */ |
362 | llwarns << "execv failure when trying to start " << cmd << llendl; | 556 | llwarns << "execv failure when trying to start " << cmd << llendl; |
363 | _exit(1); // avoid atexit() | 557 | _exit(1); // avoid atexit() |
364 | } | 558 | } else { |
365 | else | ||
366 | { | ||
367 | if (pid > 0) | 559 | if (pid > 0) |
368 | { | 560 | { |
369 | // DO NOT wait for child proc to die; we want | 561 | // wait for child proc to die |
370 | // the logger to outlive us while we quit to | 562 | int childExitStatus; |
371 | // free up the screen/keyboard/etc. | 563 | waitpid(pid, &childExitStatus, 0); |
372 | ////int childExitStatus; | 564 | } else { |
373 | ////waitpid(pid, &childExitStatus, 0); | 565 | llwarns << "fork failure." << llendl; |
566 | } | ||
567 | } | ||
568 | } | ||
569 | else | ||
570 | { | ||
571 | const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); | ||
572 | |||
573 | // Always generate the report, have the logger do the asking, and | ||
574 | // don't wait for the logger before exiting (-> total cleanup). | ||
575 | if (CRASH_BEHAVIOR_NEVER_SEND != cb) | ||
576 | { | ||
577 | // launch the actual crash logger | ||
578 | const char* ask_dialog = "-dialog"; | ||
579 | if (CRASH_BEHAVIOR_ASK != cb) | ||
580 | ask_dialog = ""; // omit '-dialog' option | ||
581 | const char * cmdargv[] = | ||
582 | {cmd.c_str(), | ||
583 | ask_dialog, | ||
584 | "-user", | ||
585 | (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(), | ||
586 | "-name", | ||
587 | LLAppViewer::instance()->getSecondLifeTitle().c_str(), | ||
588 | NULL}; | ||
589 | fflush(NULL); | ||
590 | pid_t pid = fork(); | ||
591 | if (pid == 0) | ||
592 | { // child | ||
593 | execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */ | ||
594 | llwarns << "execv failure when trying to start " << cmd << llendl; | ||
595 | _exit(1); // avoid atexit() | ||
374 | } | 596 | } |
375 | else | 597 | else |
376 | { | 598 | { |
377 | llwarns << "fork failure." << llendl; | 599 | if (pid > 0) |
600 | { | ||
601 | // DO NOT wait for child proc to die; we want | ||
602 | // the logger to outlive us while we quit to | ||
603 | // free up the screen/keyboard/etc. | ||
604 | ////int childExitStatus; | ||
605 | ////waitpid(pid, &childExitStatus, 0); | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | llwarns << "fork failure." << llendl; | ||
610 | } | ||
378 | } | 611 | } |
379 | } | 612 | } |
613 | // Sometimes signals don't seem to quit the viewer. Also, we may | ||
614 | // have been called explicitly instead of from a signal handler. | ||
615 | // Make sure we exit so as to not totally confuse the user. | ||
616 | _exit(1); // avoid atexit(), else we may re-crash in dtors. | ||
380 | } | 617 | } |
381 | // Sometimes signals don't seem to quit the viewer. Also, we may | ||
382 | // have been called explicitly instead of from a signal handler. | ||
383 | // Make sure we exit so as to not totally confuse the user. | ||
384 | _exit(1); // avoid atexit(), else we may re-crash in dtors. | ||
385 | } | 618 | } |
386 | 619 | ||
387 | bool LLAppViewerLinux::beingDebugged() | 620 | bool LLAppViewerLinux::beingDebugged() |