Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimpcriticaldialog.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimpcriticaldialog.c
 * Copyright (C) 2018  Jehan <jehan@gimp.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


/*
 * This widget is particular that I want to be able to use it
 * internally but also from an alternate tool (gimp-debug-tool). It
 * means that the implementation must stay as generic glib/GTK+ as
 * possible.
 */


#include "config.h"

#include <string.h>

#include <gtk/gtk.h>
#include <gegl.h>

#ifdef PLATFORM_OSX
#import <Cocoa/Cocoa.h>
#endif

#ifdef G_OS_WIN32
#undef DATADIR
#include <dwmapi.h>
#include <gdk/gdkwin32.h>
#include <windows.h>

#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
#endif

#include "gimpcriticaldialog.h"

#include "gimp-intl.h"
#include "gimp-version.h"


#define GIMP_CRITICAL_RESPONSE_CLIPBOARD 1
#define GIMP_CRITICAL_RESPONSE_URL       2
#define GIMP_CRITICAL_RESPONSE_RESTART   3
#define GIMP_CRITICAL_RESPONSE_DOWNLOAD  4

#define BUTTON1_TEXT _("Copy Bug Information")
#define BUTTON2_TEXT _("Open Bug Tracker")

enum
{
  PROP_0,
  PROP_LAST_VERSION,
  PROP_RELEASE_DATE
};

static void     gimp_critical_dialog_constructed  (GObject      *object);
static void     gimp_critical_dialog_finalize     (GObject      *object);
static void     gimp_critical_dialog_set_property (GObject      *object,
                                                   guint         property_id,
                                                   const GValue *value,
                                                   GParamSpec   *pspec);
static void     gimp_critical_dialog_response     (GtkDialog    *dialog,
                                                   gint          response_id);

static void     gimp_critical_dialog_copy_info    (GimpCriticalDialog *dialog);
static gboolean browser_open_url                  (GtkWindow    *window,
                                                   const gchar  *url,
                                                   GError      **error);
#ifdef G_OS_WIN32
static void     gimp_critical_dialog_realize      (GtkWidget          *widget,
                                                   GimpCriticalDialog *dialog);
#endif


G_DEFINE_TYPE (GimpCriticalDialog, gimp_critical_dialog, GTK_TYPE_DIALOG)

#define parent_class gimp_critical_dialog_parent_class


static void
gimp_critical_dialog_class_init (GimpCriticalDialogClass *klass)
{
  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);

  object_class->constructed  = gimp_critical_dialog_constructed;
  object_class->finalize     = gimp_critical_dialog_finalize;
  object_class->set_property = gimp_critical_dialog_set_property;

  dialog_class->response = gimp_critical_dialog_response;

  g_object_class_install_property (object_class, PROP_LAST_VERSION,
                                   g_param_spec_string ("last-version",
                                                        NULL, NULL, NULL,
                                                        G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
  g_object_class_install_property (object_class, PROP_RELEASE_DATE,
                                   g_param_spec_string ("release-date",
                                                        NULL, NULL, NULL,
                                                        G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
}

static void
gimp_critical_dialog_init (GimpCriticalDialog *dialog)
{
  GtkWidget      *container;
  PangoAttrList  *attrs;
  PangoAttribute *attr;

  gtk_window_set_role (GTK_WINDOW (dialog), "gimp-critical");

  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
  gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
  gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
  gtk_window_set_titlebar (GTK_WINDOW (dialog), NULL);

  dialog->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
  container         = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  gtk_container_set_border_width (GTK_CONTAINER (container), 12);
  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                      dialog->main_vbox, TRUE, TRUE, 0);
  gtk_widget_show (dialog->main_vbox);

  /* The error label. */
  dialog->top_label = gtk_label_new (NULL);
  gtk_widget_set_halign (dialog->top_label, GTK_ALIGN_START);
  gtk_label_set_ellipsize (GTK_LABEL (dialog->top_label), PANGO_ELLIPSIZE_END);
  gtk_label_set_selectable (GTK_LABEL (dialog->top_label), TRUE);
  gtk_box_pack_start (GTK_BOX (dialog->main_vbox), dialog->top_label,
                      FALSE, FALSE, 0);

  attrs = pango_attr_list_new ();
  attr  = pango_attr_weight_new (PANGO_WEIGHT_SEMIBOLD);
  pango_attr_list_insert (attrs, attr);
  gtk_label_set_attributes (GTK_LABEL (dialog->top_label), attrs);
  pango_attr_list_unref (attrs);

  gtk_widget_show (dialog->top_label);

  dialog->center_label = gtk_label_new (NULL);

  gtk_widget_set_halign (dialog->center_label, GTK_ALIGN_START);
  gtk_label_set_selectable (GTK_LABEL (dialog->center_label), TRUE);
  gtk_box_pack_start (GTK_BOX (dialog->main_vbox), dialog->center_label,
                      FALSE, FALSE, 0);
  gtk_widget_show (dialog->center_label);

  dialog->bottom_label = gtk_label_new (NULL);
  gtk_widget_set_halign (dialog->bottom_label, GTK_ALIGN_START);
  gtk_box_pack_start (GTK_BOX (dialog->main_vbox), dialog->bottom_label, FALSE, FALSE, 0);

  attrs = pango_attr_list_new ();
  attr  = pango_attr_style_new (PANGO_STYLE_ITALIC);
  pango_attr_list_insert (attrs, attr);
  gtk_label_set_attributes (GTK_LABEL (dialog->bottom_label), attrs);
  pango_attr_list_unref (attrs);
  gtk_widget_show (dialog->bottom_label);

  dialog->pid      = 0;
  dialog->program  = NULL;
}

static void
gimp_critical_dialog_constructed (GObject *object)
{
  GimpCriticalDialog *dialog = GIMP_CRITICAL_DIALOG (object);
  GtkWidget          *scrolled;
  GtkTextBuffer      *buffer;
  gchar              *version;
  gchar              *text;

  /* Bug details for developers. */
  scrolled = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
                                       GTK_SHADOW_IN);
  gtk_widget_set_size_request (scrolled, -1, 200);

  if (dialog->last_version)
    {
      GtkWidget *expander;
      GtkWidget *vbox;
      GtkWidget *button;

      expander = gtk_expander_new (_("See bug details"));
      gtk_box_pack_start (GTK_BOX (dialog->main_vbox), expander, TRUE, TRUE, 0);
      gtk_widget_show (expander);

      vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
      gtk_container_add (GTK_CONTAINER (expander), vbox);
      gtk_widget_show (vbox);

      gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
      gtk_widget_show (scrolled);

      button = gtk_button_new_with_label (BUTTON1_TEXT);
      g_signal_connect_swapped (button, "clicked",
                                G_CALLBACK (gimp_critical_dialog_copy_info),
                                dialog);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 6);
      gtk_widget_show (button);

      gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                              _("Go to _Download page"), GIMP_CRITICAL_RESPONSE_DOWNLOAD,
                              _("_Close"),               GTK_RESPONSE_CLOSE,
                              NULL);

      /* Recommend an update. */
      text = g_strdup_printf (_("A new version of GIMP (%s) was released on %s.\n"
                                "It is recommended to update."),
                              dialog->last_version, dialog->release_date);
      gtk_label_set_text (GTK_LABEL (dialog->center_label), text);
      g_free (text);

      text = _("You are running an unsupported version!");
      gtk_label_set_text (GTK_LABEL (dialog->bottom_label), text);
    }
  else
    {
      /* Pack directly (and well visible) the bug details. */
      gtk_box_pack_start (GTK_BOX (dialog->main_vbox), scrolled, TRUE, TRUE, 6);
      gtk_widget_show (scrolled);

      gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                              BUTTON1_TEXT, GIMP_CRITICAL_RESPONSE_CLIPBOARD,
                              BUTTON2_TEXT, GIMP_CRITICAL_RESPONSE_URL,
                              _("_Close"),  GTK_RESPONSE_CLOSE,
                              NULL);

      /* Generic "report a bug" instructions. */
      text = g_strdup_printf ("%s\n"
                              " \xe2\x80\xa2 %s %s\n"
                              " \xe2\x80\xa2 %s %s\n"
                              " \xe2\x80\xa2 %s\n"
                              " \xe2\x80\xa2 %s\n"
                              " \xe2\x80\xa2 %s\n"
                              " \xe2\x80\xa2 %s",
                              _("To help us improve GIMP, you can report the bug with "
                                "these simple steps:"),
                              _("Copy the bug information to the clipboard by clicking: "),
                              BUTTON1_TEXT,
                              _("Open our bug tracker in the browser by clicking: "),
                              BUTTON2_TEXT,
                              _("Create a login if you don't have one yet."),
                              _("Paste the clipboard text in a new bug report."),
                              _("Add relevant information in English in the bug report "
                                "explaining what you were doing when this error occurred."),
                              _("This error may have left GIMP in an inconsistent state. "
                                "It is advised to save your work and restart GIMP."));
      gtk_label_set_text (GTK_LABEL (dialog->center_label), text);
      g_free (text);

      text = _("You can also close the dialog directly but "
               "reporting bugs is the best way to make your "
               "software awesome.");
      gtk_label_set_text (GTK_LABEL (dialog->bottom_label), text);
    }

  buffer = gtk_text_buffer_new (NULL);
  version = gimp_version (TRUE, FALSE);
  text = g_strdup_printf ("<!-- %s -->\n\n\n```\n%s\n```",
                          _("Copy-paste this whole debug data to report to developers"),
                          version);
  gtk_text_buffer_set_text (buffer, text, -1);
  g_free (version);
  g_free (text);

  dialog->details = gtk_text_view_new_with_buffer (buffer);
  g_object_unref (buffer);
  gtk_text_view_set_editable (GTK_TEXT_VIEW (dialog->details), FALSE);
  gtk_widget_show (dialog->details);
  gtk_container_add (GTK_CONTAINER (scrolled), dialog->details);
}

/* Copied from app/widgets/gimpwidgets-utils.c, to reduce dependency
 * on internal GIMP procedures */

#ifdef G_OS_WIN32
static void
gimp_critical_dialog_realize (GtkWidget          *widget,
                              GimpCriticalDialog *dialog)
{
  HWND             hwnd;
  GdkWindow       *window        = NULL;
  GtkStyleContext *style;
  GdkRGBA         *color         = NULL;
  gboolean         use_dark_mode = FALSE;

  window = gtk_widget_get_window (GTK_WIDGET (widget));
  if (window)
    {
      /* Workaround if we don't have access to GimpGuiConfig.
       * If the background color is below the threshold, then we're
       * likely in dark mode.
       */

      style = gtk_widget_get_style_context (widget);
      gtk_style_context_get (style, gtk_style_context_get_state (style),
                             GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color,
                             NULL);
      if (color)
        {
          if (color->red < 0.5 && color->green < 0.5 && color->blue < 0.5)
            use_dark_mode = TRUE;

          gdk_rgba_free (color);
        }

      hwnd = (HWND) gdk_win32_window_get_handle (window);
      DwmSetWindowAttribute (hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
                              &use_dark_mode, sizeof (use_dark_mode));
    }
}
#endif


static void
gimp_critical_dialog_finalize (GObject *object)
{
  GimpCriticalDialog *dialog = GIMP_CRITICAL_DIALOG (object);

  if (dialog->program)
    g_free (dialog->program);
  if (dialog->last_version)
    g_free (dialog->last_version);
  if (dialog->release_date)
    g_free (dialog->release_date);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gimp_critical_dialog_set_property (GObject      *object,
                                   guint         property_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
{
  GimpCriticalDialog *dialog = GIMP_CRITICAL_DIALOG (object);

  switch (property_id)
    {
    case PROP_LAST_VERSION:
      dialog->last_version = g_value_dup_string (value);
      break;
    case PROP_RELEASE_DATE:
      dialog->release_date = g_value_dup_string (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_critical_dialog_copy_info (GimpCriticalDialog *dialog)
{
  GtkClipboard *clipboard;

  clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
                                             GDK_SELECTION_CLIPBOARD);
  if (clipboard)
    {
      GtkTextBuffer *buffer;
      gchar         *text;
      GtkTextIter    start;
      GtkTextIter    end;

      buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->details));
      gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
      gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
      text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
      gtk_clipboard_set_text (clipboard, text, -1);
      g_free (text);
    }
}

/* XXX This is taken straight from plug-ins/common/web-browser.c
 *
 * This really sucks but this class also needs to be called by
 * tools/gimp-debug-tool.c as a separate process and therefore cannot
 * make use of the PDB. Anyway shouldn't we just move this as a utils
 * function?  Why does such basic feature as opening a URL in a
 * cross-platform way need to be a plug-in?
 */

static gboolean
browser_open_url (GtkWindow    *window,
                  const gchar  *url,
                  GError      **error)
{
#ifdef G_OS_WIN32

  HINSTANCE hinst = ShellExecute (GetDesktopWindow(),
                                  "open", url, NULL, NULL, SW_SHOW);

  if ((intptr_t) hinst <= 32)
    {
      const gchar *err;

      switch ((intptr_t) hinst)
        {
          case 0 :
            err = _("The operating system is out of memory or resources.");
            break;
          case ERROR_FILE_NOT_FOUND :
            err = _("The specified file was not found.");
            break;
          case ERROR_PATH_NOT_FOUND :
            err = _("The specified path was not found.");
            break;
          case ERROR_BAD_FORMAT :
            err = _("The .exe file is invalid (non-Microsoft Win32 .exe or error in .exe image).");
            break;
          case SE_ERR_ACCESSDENIED :
            err = _("The operating system denied access to the specified file.");
            break;
          case SE_ERR_ASSOCINCOMPLETE :
            err = _("The file name association is incomplete or invalid.");
            break;
          case SE_ERR_DDEBUSY :
            err = _("DDE transaction busy");
            break;
          case SE_ERR_DDEFAIL :
            err = _("The DDE transaction failed.");
            break;
          case SE_ERR_DDETIMEOUT :
            err = _("The DDE transaction timed out.");
            break;
          case SE_ERR_DLLNOTFOUND :
            err = _("The specified DLL was not found.");
            break;
          case SE_ERR_NOASSOC :
            err = _("There is no application associated with the given file name extension.");
            break;
          case SE_ERR_OOM :
            err = _("There was not enough memory to complete the operation.");
            break;
          case SE_ERR_SHARE:
            err = _("A sharing violation occurred.");
            break;
          default :
            err = _("Unknown Microsoft Windows error.");
        }

      g_set_error (error, 0, 0, _("Failed to open '%s': %s"), url, err);

      return FALSE;
    }

  return TRUE;

#elif defined(PLATFORM_OSX)

  NSURL    *ns_url;
  gboolean  retval;

  @autoreleasepool
    {
      ns_url = [NSURL URLWithString: [NSString stringWithUTF8String: url]];
      retval = [[NSWorkspace sharedWorkspace] openURL: ns_url];
    }

  return retval;

#else

  return gtk_show_uri_on_window (window,
                                 url,
                                 GDK_CURRENT_TIME,
                                 error);

#endif
}

static void
gimp_critical_dialog_response (GtkDialog *dialog,
                               gint       response_id)
{
  GimpCriticalDialog *critical = GIMP_CRITICAL_DIALOG (dialog);
  const gchar        *url      = NULL;

  switch (response_id)
    {
    case GIMP_CRITICAL_RESPONSE_CLIPBOARD:
      gimp_critical_dialog_copy_info (critical);
      break;

    case GIMP_CRITICAL_RESPONSE_DOWNLOAD:
#ifdef GIMP_UNSTABLE
      url = "https://www.gimp.org/downloads/devel/";
#else
      url = "https://www.gimp.org/downloads/";
#endif
    case GIMP_CRITICAL_RESPONSE_URL:
      if (url == NULL)
        {
          gchar *temp = g_ascii_strdown (BUG_REPORT_URL, -1);

          /* Only accept custom web links. */
          if (g_str_has_prefix (temp, "http://") ||
              g_str_has_prefix (temp, "https://"))
            url = BUG_REPORT_URL;
          else
            /* XXX Ideally I'd find a way to prefill the bug report
             * through the URL or with POST data. But I could not find
             * any. Anyway since we may soon ditch bugzilla to follow
             * GNOME infrastructure changes, I don't want to waste too
             * much time digging into it.
             */

            url = PACKAGE_BUGREPORT;

          g_free (temp);
        }

      browser_open_url (GTK_WINDOW (dialog), url, NULL);
      break;

    case GIMP_CRITICAL_RESPONSE_RESTART:
      {
        gchar *args[2] = { critical->program , NULL };

#ifndef G_OS_WIN32
        /* It is unneeded to kill the process on Win32. This was run
         * as an async call and the main process should already be
         * dead by now.
         */

        if (critical->pid > 0)
          kill ((pid_t ) critical->pid, SIGINT);
#endif
        if (critical->program)
          g_spawn_async (NULL, args, NULL, G_SPAWN_DEFAULT,
                         NULL, NULL, NULL, NULL);
      }
      /* Fall through. */
    case GTK_RESPONSE_DELETE_EVENT:
    case GTK_RESPONSE_CLOSE:
    default:
      gtk_widget_destroy (GTK_WIDGET (dialog));
      break;
    }
}

/*  public functions  */

GtkWidget *
gimp_critical_dialog_new (const gchar *title,
                          const gchar *last_version,
                          gint64       release_timestamp)
{
  GtkWidget *dialog;
  gchar     *date = NULL;

  g_return_val_if_fail (title != NULL, NULL);

  if (release_timestamp > 0)
    {
      GDateTime *datetime;

      datetime = g_date_time_new_from_unix_local (release_timestamp);
      date = g_date_time_format (datetime, "%x");
      g_date_time_unref (datetime);
    }

  dialog = g_object_new (GIMP_TYPE_CRITICAL_DIALOG,
                         "title",        title,
                         "last-version", last_version,
                         "release-date", date,
                         NULL);
  g_free (date);

#ifdef G_OS_WIN32
  g_signal_connect_object (dialog, "realize",
                           G_CALLBACK (gimp_critical_dialog_realize),
                           NULL, 0);
#endif

  return dialog;
}

void
gimp_critical_dialog_add (GtkWidget   *dialog,
                          const gchar *message,
                          const gchar *trace,
                          gboolean     is_fatal,
                          const gchar *program,
                          gint         pid)
{
  GimpCriticalDialog *critical;
  GtkTextBuffer      *buffer;
  GtkTextIter         end;
  gchar              *text;

  if (! GIMP_IS_CRITICAL_DIALOG (dialog) || ! message)
    {
      /* This is a bit hackish. We usually should use
       * g_return_if_fail(). But I don't want to end up in a critical
       * recursing loop if our code had bugs. We would crash GIMP with
       * a CRITICAL which would otherwise not have necessarily ended up
       * in a crash.
       */

      return;
    }
  critical = GIMP_CRITICAL_DIALOG (dialog);

  /* The user text, which should be localized. */
  if (is_fatal)
    {
      text = g_strdup_printf (_("GIMP crashed with a fatal error: %s"),
                              message);
    }
  else if (! gtk_label_get_text (GTK_LABEL (critical->top_label)) ||
           strlen (gtk_label_get_text (GTK_LABEL (critical->top_label))) == 0)
    {
      /* First error. Let's just display it. */
      text = g_strdup_printf (_("GIMP encountered an error: %s"),
                              message);
    }
  else
    {
      /* Let's not display all errors. They will be in the bug report
       * part anyway.
       */

      text = g_strdup_printf (_("GIMP encountered several critical errors!"));
    }
  gtk_label_set_text (GTK_LABEL (critical->top_label),
                      text);
  g_free (text);

  if (is_fatal && ! critical->last_version)
    {
      /* Same text as before except that we don't need the last point
       * about saving and restarting since anyway we are crashing and
       * manual saving is not possible anymore (or even advisable since
       * if it fails, one may corrupt files).
       */

      text = g_strdup_printf ("%s\n"
                              " \xe2\x80\xa2 %s \"%s\"\n"
                              " \xe2\x80\xa2 %s \"%s\"\n"
                              " \xe2\x80\xa2 %s\n"
                              " \xe2\x80\xa2 %s\n"
                              " \xe2\x80\xa2 %s",
                              _("To help us improve GIMP, you can report the bug with "
                                "these simple steps:"),
                              _("Copy the bug information to the clipboard by clicking: "),
                              BUTTON1_TEXT,
                              _("Open our bug tracker in the browser by clicking: "),
                              BUTTON2_TEXT,
                              _("Create a login if you don't have one yet."),
                              _("Paste the clipboard text in a new bug report."),
                              _("Add relevant information in English in the bug report "
                                "explaining what you were doing when this error occurred."));
      gtk_label_set_text (GTK_LABEL (critical->center_label), text);
      g_free (text);
    }

  /* The details text is untranslated on purpose. This is the message
   * meant to go to clipboard for the bug report. It has to be in
   * English.
   */

  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (critical->details));
  gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
  if (trace)
    text = g_strdup_printf ("\n> %s\n\nStack trace:\n```\n%s\n```", message, trace);
  else
    text = g_strdup_printf ("\n> %s\n", message);
  gtk_text_buffer_insert (buffer, &end, text, -1);
  g_free (text);

  /* Finally when encountering a fatal message, propose one more button
   * to restart GIMP.
   */

  if (is_fatal)
    {
      gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                              _("_Restart GIMP"), GIMP_CRITICAL_RESPONSE_RESTART,
                              NULL);
      critical->program = g_strdup (program);
      critical->pid     = pid;
    }
}

Messung
CHZG
821009793

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417336