Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gtkapplication-win32.c

  Sprache: C
 

/*
 * GtkApplication implementation for Win32.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 * SPDX-FileCopyrightText: 2025-2026 GNOME Foundation
 *
 * ## LOGOFF inhibition
 * https://learn.microsoft.com/en-us/windows/win32/shutdown/logging-off
 * It seems that only visible windows are able to block logout requests,
 * so delegate the events handling to the HWND of each application window.
 * Requests counters are managed on GdkWin32 side.
 * Because we need to track added and removed windows, only windows attached
 * to the application are supported.
 * Using SetProcessShutdownParameters() with higher priority will ensure the
 * mainloop catches and responds to session events before all other HWNDs.
 *
 * ## IDLE and SUSPEND inhibition
 * https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-powersetrequest
 * Requests counters are automatically managed by PowerSetRequest().
 * It could be possible to use the old SetThreadExecutionState() API instead,
 * but this one needs to be called periodically.
 * The underlying Win32 APIs need a reason string, if not provided the
 * inhibition will be ignored.
 * Note that power requests will be cancelled if the user manually stops them,
 * e.g. by sleeping from the start menu or by closing the lid.
 */


#define WIN32_LEAN_AND_MEAN

#include "config.h"

#include "gtkapplicationprivate.h"
#include "gtknative.h"

#include "win32/gdkprivate-win32.h"

#include <windows.h>


typedef GtkApplicationImplClass GtkApplicationImplWin32Class;

typedef struct
{
  GtkApplicationImpl impl;
  GSList *inhibitors;
  guint next_cookie;
} GtkApplicationImplWin32;

typedef struct
{
  guint cookie;
  GtkApplicationInhibitFlags flags;
  HANDLE pwr_handle;
  GdkSurface *surface;
} GtkApplicationWin32Inhibitor;

G_DEFINE_TYPE (GtkApplicationImplWin32, gtk_application_impl_win32, GTK_TYPE_APPLICATION_IMPL)


static void
appwin32_inhibitor_free (GtkApplicationWin32Inhibitor *inhibitor)
{
  CloseHandle (inhibitor->pwr_handle);
  g_clear_object (&inhibitor->surface);
  g_free (inhibitor);
}

static void
cb_appwin32_session_query_end (void)
{
  GApplication *application = g_application_get_default ();

  if (GTK_IS_APPLICATION (application))
    g_signal_emit_by_name (application, "query-end");
}

static void
cb_appwin32_session_end (void)
{
  GApplication *application = g_application_get_default ();

  if (G_IS_APPLICATION (application))
    g_application_quit (application);
}

static void
gtk_application_impl_win32_shutdown (GtkApplicationImpl *impl)
{
  GtkApplicationImplWin32 *appwin32 = (GtkApplicationImplWin32 *) impl;
  GList *iter;

  for (iter = gtk_application_get_windows (impl->application); iter; iter = iter->next)
    {
      if (!gtk_widget_get_realized (GTK_WIDGET (iter->data)))
        continue;

      gdk_win32_surface_set_session_callbacks (gtk_native_get_surface (GTK_NATIVE (iter->data)),
                                               NULL,
                                               NULL);
    }

  g_slist_free_full (appwin32->inhibitors, (GDestroyNotify) appwin32_inhibitor_free);
  appwin32->inhibitors = NULL;
}

static void
gtk_application_impl_win32_handle_window_realize (GtkApplicationImpl *impl,
                                                  GtkWindow          *window)
{
  g_return_if_fail (GTK_IS_WINDOW (window));

  gdk_win32_surface_set_session_callbacks (gtk_native_get_surface (GTK_NATIVE (window)),
                                           cb_appwin32_session_query_end,
                                           cb_appwin32_session_end);
}

static void
gtk_application_impl_win32_window_added (GtkApplicationImpl *impl,
                                         GtkWindow          *window,
                                         GVariant           *state)
{
  g_return_if_fail (GTK_IS_WINDOW (window));

  if (!gtk_widget_get_realized (GTK_WIDGET (window)))
    return;   /* no surface yet, wait for handle_window_realize */

  gdk_win32_surface_set_session_callbacks (gtk_native_get_surface (GTK_NATIVE (window)),
                                           cb_appwin32_session_query_end,
                                           cb_appwin32_session_end);
}

static void
gtk_application_impl_win32_window_removed (GtkApplicationImpl *impl,
                                           GtkWindow          *window)
{
  GtkApplicationImplWin32 *appwin32 = (GtkApplicationImplWin32 *) impl;
  GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (window));
  GSList *iter;

  if (!surface)
    return;

  gdk_win32_surface_set_session_callbacks (surface,
                                           NULL,
                                           NULL);

  /* Ensure we don't keep a ref of the surface in the inhibitors,
   * should the window get removed before uninhibit is called.
   */

  for (iter = appwin32->inhibitors; iter; iter = iter->next)
    {
      GtkApplicationWin32Inhibitor *inhibitor = iter->data;

      if ((inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT) &&
          (inhibitor->surface == surface))
        {
          gdk_win32_surface_uninhibit_logout (inhibitor->surface);
          inhibitor->flags &= ~GTK_APPLICATION_INHIBIT_LOGOUT;
          g_clear_object (&inhibitor->surface);
        }
    }
}

static guint
gtk_application_impl_win32_inhibit (GtkApplicationImpl         *impl,
                                    GtkWindow                  *window,
                                    GtkApplicationInhibitFlags  flags,
                                    const char                 *reason)
{
  GtkApplicationImplWin32 *appwin32 = (GtkApplicationImplWin32 *) impl;
  GtkApplicationWin32Inhibitor *inhibitor = g_new0 (GtkApplicationWin32Inhibitor, 1);
  wchar_t *reason_w = g_utf8_to_utf16 (reason, -1, NULL, NULL, NULL);

  inhibitor->cookie = ++appwin32->next_cookie;

  if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
    {
      if (GTK_IS_WINDOW (window) &&
          impl->application == gtk_window_get_application (window))
        {
          GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (window));

          if (gdk_win32_surface_inhibit_logout (surface, reason_w))
            {
              inhibitor->surface = g_object_ref (surface);
              inhibitor->flags |= GTK_APPLICATION_INHIBIT_LOGOUT;
            }
        }
      else
        g_warning ("Logout inhibition is only supported on application windows");
    }

  if (flags & (GTK_APPLICATION_INHIBIT_SUSPEND | GTK_APPLICATION_INHIBIT_IDLE))
    {
      REASON_CONTEXT context;

      memset (&context, 0sizeof (context));
      context.Version = POWER_REQUEST_CONTEXT_VERSION;
      context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
      context.Reason.SimpleReasonString = reason_w;

      inhibitor->pwr_handle = PowerCreateRequest (&context);

      if (flags & GTK_APPLICATION_INHIBIT_SUSPEND)
        {
          if (PowerSetRequest (inhibitor->pwr_handle, PowerRequestSystemRequired))
            inhibitor->flags |= GTK_APPLICATION_INHIBIT_SUSPEND;
          else
            g_warning ("Failed to apply suspend inhibition");
        }

      if (flags & GTK_APPLICATION_INHIBIT_IDLE)
        {
          if (PowerSetRequest (inhibitor->pwr_handle, PowerRequestDisplayRequired))
            inhibitor->flags |= GTK_APPLICATION_INHIBIT_IDLE;
          else
            g_warning ("Failed to apply idle inhibition");
        }
    }

  g_free (reason_w);

  if (inhibitor->flags)
    {
      appwin32->inhibitors = g_slist_prepend (appwin32->inhibitors, inhibitor);
      return inhibitor->cookie;
    }

  appwin32_inhibitor_free (inhibitor);
  return 0;
}

static void
gtk_application_impl_win32_uninhibit (GtkApplicationImpl *impl, guint cookie)
{
  GtkApplicationImplWin32 *appwin32 = (GtkApplicationImplWin32 *) impl;
  GSList *iter;

  for (iter = appwin32->inhibitors; iter; iter = iter->next)
    {
      GtkApplicationWin32Inhibitor *inhibitor = iter->data;

      if (inhibitor->cookie == cookie)
        {
          if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
            gdk_win32_surface_uninhibit_logout (inhibitor->surface);

          if (inhibitor->flags & GTK_APPLICATION_INHIBIT_SUSPEND)
            PowerClearRequest (inhibitor->pwr_handle, PowerRequestSystemRequired);

          if (inhibitor->flags & GTK_APPLICATION_INHIBIT_IDLE)
            PowerClearRequest (inhibitor->pwr_handle, PowerRequestDisplayRequired);

          appwin32_inhibitor_free (inhibitor);
          appwin32->inhibitors = g_slist_delete_link (appwin32->inhibitors, iter);
          return;
        }
    }

  g_warning ("Invalid inhibitor cookie: %d", cookie);
}

static gboolean
gtk_application_impl_win32_is_inhibited (GtkApplicationImpl         *impl,
                                         GtkApplicationInhibitFlags  flags)
{
  GtkApplicationImplWin32 *appwin32 = (GtkApplicationImplWin32 *) impl;
  GtkApplicationInhibitFlags active_flags = 0;
  GSList *iter;

  for (iter = appwin32->inhibitors; iter; iter = iter->next)
    {
      GtkApplicationWin32Inhibitor *inhibitor = iter->data;
      active_flags |= inhibitor->flags;
    }

  return (active_flags & flags) == flags;
}

static void
gtk_application_impl_win32_class_init (GtkApplicationImplClass *klass)
{
  klass->shutdown = gtk_application_impl_win32_shutdown;
  klass->handle_window_realize = gtk_application_impl_win32_handle_window_realize;
  klass->window_added = gtk_application_impl_win32_window_added;
  klass->window_removed = gtk_application_impl_win32_window_removed;
  klass->inhibit = gtk_application_impl_win32_inhibit;
  klass->uninhibit = gtk_application_impl_win32_uninhibit;
  klass->is_inhibited = gtk_application_impl_win32_is_inhibited;
}

static void
gtk_application_impl_win32_init (GtkApplicationImplWin32 *appwin32)
{
  DWORD dwLevel, dwFlags;

  appwin32->next_cookie = 0;
  appwin32->inhibitors = NULL;

  if (GetProcessShutdownParameters (&dwLevel, &dwFlags))
    {
      dwLevel = MAX (dwLevel, 0x300);
      SetProcessShutdownParameters (dwLevel, dwFlags);
    }
}

Messung V0.5 in Prozent
C=99 H=92 G=95

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

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

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik