Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/widget/gtk/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 12 kB image not shown  

Quelle  nsWindowX11.cpp   Sprache: C

 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "nsWindow.h"
#include "nsWindowX11.h"

#include "mozilla/gfx/gfxVars.h"
#include "mozilla/PodOperations.h"
#include <gdk/gdkkeysyms-compat.h>
#include <X11/Xatom.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include "gfxXlibSurface.h"
#include "GLContextGLX.h"  // for GLContextGLX::FindVisual()
#include "GLContextEGL.h"  // for GLContextEGL::FindVisual()
#include "WindowSurfaceX11Image.h"
#include "WindowSurfaceX11SHM.h"

using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::widget;
using mozilla::gl::GLContextEGL;
using mozilla::gl::GLContextGLX;

void nsWindowX11::GetWorkspaceID(nsAString& workspaceID) {
  workspaceID.Truncate();

  if (!mShell) {
    return;
  }

  LOG("nsWindow::GetWorkspaceID()\n");

  // Get the gdk window for this widget.
  GdkWindow* gdk_window = GetToplevelGdkWindow();
  if (!gdk_window) {
    LOG("  missing Gdk window, quit.");
    return;
  }

  if (WorkspaceManagementDisabled()) {
    LOG("  WorkspaceManagementDisabled, quit.");
    return;
  }

  GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
  GdkAtom type_returned;
  int format_returned;
  int length_returned;
  long* wm_desktop;

  if (!gdk_property_get(gdk_window, gdk_atom_intern("_NET_WM_DESKTOP", FALSE),
                        cardinal_atom,
                        0,          // offset
                        INT32_MAX,  // length
                        FALSE,      // delete
                        &type_returned, &format_returned, &length_returned,
                        (guchar**)&wm_desktop)) {
    LOG("  gdk_property_get() failed, quit.");
    return;
  }

  LOG("  got workspace ID %d", (int32_t)wm_desktop[0]);
  workspaceID.AppendInt((int32_t)wm_desktop[0]);
  g_free(wm_desktop);
}

void nsWindowX11::MoveToWorkspace(const nsAString& workspaceIDStr) {
  nsresult rv = NS_OK;
  int32_t workspaceID = workspaceIDStr.ToInteger(&rv);

  LOG("nsWindow::MoveToWorkspace() ID %d", workspaceID);
  if (NS_FAILED(rv) || !workspaceID || !mShell) {
    LOG("  MoveToWorkspace disabled, quit");
    return;
  }

  // Get the gdk window for this widget.
  GdkWindow* gdk_window = GetToplevelGdkWindow();
  if (!gdk_window) {
    LOG("  failed to get GdkWindow, quit.");
    return;
  }

  // This code is inspired by some found in the 'gxtuner' project.
  // https://github.com/brummer10/gxtuner/blob/792d453da0f3a599408008f0f1107823939d730d/deskpager.cpp#L50
  XEvent xevent;
  Display* xdisplay = gdk_x11_get_default_xdisplay();
  GdkScreen* screen = gdk_window_get_screen(gdk_window);
  Window root_win = GDK_WINDOW_XID(gdk_screen_get_root_window(screen));
  GdkDisplay* display = gdk_window_get_display(gdk_window);
  Atom type = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WM_DESKTOP");

  xevent.type = ClientMessage;
  xevent.xclient.type = ClientMessage;
  xevent.xclient.serial = 0;
  xevent.xclient.send_event = TRUE;
  xevent.xclient.display = xdisplay;
  xevent.xclient.window = GDK_WINDOW_XID(gdk_window);
  xevent.xclient.message_type = type;
  xevent.xclient.format = 32;
  xevent.xclient.data.l[0] = workspaceID;
  xevent.xclient.data.l[1] = X11CurrentTime;
  xevent.xclient.data.l[2] = 0;
  xevent.xclient.data.l[3] = 0;
  xevent.xclient.data.l[4] = 0;

  XSendEvent(xdisplay, root_win, FALSE,
             SubstructureNotifyMask | SubstructureRedirectMask, &xevent);

  XFlush(xdisplay);
  LOG("  moved to workspace");
}

Window nsWindowX11::GetX11Window() {
  return gdk_x11_window_get_xid(mGdkWindow);
}

// Configure GL visual on X11.
bool nsWindowX11::ConfigureX11GLVisual() {
  auto* screen = gtk_widget_get_screen(mShell);
  int visualId = 0;
  bool haveVisual = false;

  if (gfxVars::UseEGL()) {
    haveVisual = GLContextEGL::FindVisual(&visualId);
  }

  // We are on GLX or use it as a fallback on Mesa, see
  // https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
  if (!haveVisual) {
    auto* display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(mShell));
    int screenNumber = GDK_SCREEN_XNUMBER(screen);
    haveVisual = GLContextGLX::FindVisual(display, screenNumber, &visualId);
  }

  GdkVisual* gdkVisual = nullptr;
  if (haveVisual) {
    // If we're using CSD, rendering will go through mContainer, but
    // it will inherit this visual as it is a child of mShell.
    gdkVisual = gdk_x11_screen_lookup_visual(screen, visualId);
  }
  if (!gdkVisual) {
    NS_WARNING("We're missing X11 Visual!");
    // We try to use a fallback alpha visual
    GdkScreen* screen = gtk_widget_get_screen(mShell);
    gdkVisual = gdk_screen_get_rgba_visual(screen);
  }
  if (gdkVisual) {
    gtk_widget_set_visual(mShell, gdkVisual);
    mHasAlphaVisual = true;
    return true;
  }

  return false;
}

void nsWindowX11::CreateNative() {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  gtk_widget_set_double_buffered(GTK_WIDGET(mContainer), FALSE);
#pragma GCC diagnostic pop

  mSurfaceProvider.Initialize(GetX11Window());
}

void nsWindowX11::ConfigureToplevelWindowNative() {
  // Set window manager hint to keep fullscreen windows composited.
  //
  // If the window were to get unredirected, there could be visible
  // tearing because Gecko does not align its framebuffer updates with
  // vblank.
  //
  // This must be (re-)applied whenever the shell's X window is created,
  // including after CSD-triggered re-realize in SetCustomTitlebar().
  SetCompositorHint(GTK_WIDGET_COMPOSITED_ENABLED);
}

void nsWindowX11::DestroyNative() { UnlockNativePointer(); }

void nsWindowX11::SetCompositorHint(WindowComposeRequest aState) {
  gulong value = aState;
  GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
  gdk_property_change(GetToplevelGdkWindow(),
                      gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE),
                      cardinal_atom,
                      32,  // format
                      GDK_PROP_MODE_REPLACE, (guchar*)&value, 1);
}

/* XApp progress support currently works by setting a property
 * on a window with this Atom name.  A supporting window manager
 * will notice this and pass it along to whatever handling has
 * been implemented on that end (e.g. passing it on to a taskbar
 * widget.)  There is no issue if WM support is lacking, this is
 * simply ignored in that case.
 *
 * See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c
 * for further details.
 */


#define PROGRESS_HINT "_NET_WM_XAPP_PROGRESS"

static void set_window_hint_cardinal(Window xid, const gchar* atom_name,
                                     gulong cardinal) {
  GdkDisplay* display;
  display = gdk_display_get_default();
  if (cardinal > 0) {
    XChangeProperty(GDK_DISPLAY_XDISPLAY(display), xid,
                    gdk_x11_get_xatom_by_name_for_display(display, atom_name),
                    XA_CARDINAL, 32, PropModeReplace, (guchar*)&cardinal, 1);
  } else {
    XDeleteProperty(GDK_DISPLAY_XDISPLAY(display), xid,
                    gdk_x11_get_xatom_by_name_for_display(display, atom_name));
  }
}

void nsWindowX11::SetProgress(unsigned long progressPercent) {
  progressPercent = MIN(progressPercent, 100);
  set_window_hint_cardinal(GDK_WINDOW_XID(GetToplevelGdkWindow()),
                           PROGRESS_HINT, progressPercent);
}

static bool SupportsPointerBarriers(Display* aDisplay) {
  MOZ_ASSERT(StaticPrefs::dom_pointer_lock_native_lock_enabled());
  // XXX We expect the capability doesn't change as we use only one display
  // everywhere.
  static const bool sSupported = [&] {
    int eventBase = -1;
    int errorBase = -1;
    if (!XFixesQueryExtension(aDisplay, &eventBase, &errorBase)) {
      return false;
    }

    int major = 0;
    int minor = 0;
    if (!XFixesQueryVersion(aDisplay, &major, &minor)) {
      return false;
    }

    return major >= 5;
  }();
  return sSupported;
}

void nsWindowX11::UpdateNativePointerBarriers() {
  if (!StaticPrefs::dom_pointer_lock_native_lock_enabled()) {
    MOZ_ASSERT(!mIsNativePointerLocked);
    MOZ_ASSERT(!mNativePointerBarriers);
    return;
  }

  if (NS_WARN_IF(!mGdkWindow)) {
    return;
  }

  Display* display = GDK_DISPLAY_XDISPLAY(gdk_window_get_display(mGdkWindow));
  if (NS_WARN_IF(!SupportsPointerBarriers(display))) {
    MOZ_ASSERT(!mNativePointerBarriers);
    return;
  }

  if (mNativePointerBarriers) {
    XFixesDestroyPointerBarrier(display, mNativePointerBarriers->mLeft);
    XFixesDestroyPointerBarrier(display, mNativePointerBarriers->mRight);
    XFixesDestroyPointerBarrier(display, mNativePointerBarriers->mTop);
    XFixesDestroyPointerBarrier(display, mNativePointerBarriers->mBottom);
    mNativePointerBarriers.reset();
  }

  if (mIsNativePointerLocked) {
    Window window = GetX11Window();
    mNativePointerBarriers.emplace(
        XFixesCreatePointerBarrier(
            display, window, mClientArea.X(), mClientArea.Y(), mClientArea.X(),
            mClientArea.YMost(), BarrierPositiveX, 0, nullptr),
        XFixesCreatePointerBarrier(display, window, mClientArea.XMost(),
                                   mClientArea.Y(), mClientArea.XMost(),
                                   mClientArea.YMost(), BarrierNegativeX, 0,
                                   nullptr),
        XFixesCreatePointerBarrier(
            display, window, mClientArea.X(), mClientArea.Y(),
            mClientArea.XMost(), mClientArea.Y(), BarrierPositiveY, 0, nullptr),
        XFixesCreatePointerBarrier(display, window, mClientArea.X(),
                                   mClientArea.YMost(), mClientArea.XMost(),
                                   mClientArea.YMost(), BarrierNegativeY, 0,
                                   nullptr));
  }
}

void nsWindowX11::LockNativePointer(
    NativePointerLockMode aNativePointerLockMode) {
  if (!StaticPrefs::dom_pointer_lock_native_lock_enabled()) {
    MOZ_ASSERT(!mIsNativePointerLocked);
    MOZ_ASSERT(!mNativePointerBarriers);
    return;
  }

  if (mIsNativePointerLocked) {
    MOZ_ASSERT(mNativePointerBarriers);
    return;
  }

  mIsNativePointerLocked = true;
  UpdateNativePointerBarriers();
}

void nsWindowX11::UnlockNativePointer() {
  if (!mIsNativePointerLocked) {
    MOZ_ASSERT(!mNativePointerBarriers);
    return;
  }
  MOZ_ASSERT(StaticPrefs::dom_pointer_lock_native_lock_enabled());
  mIsNativePointerLocked = false;
  UpdateNativePointerBarriers();
}

void nsWindowX11::NativeShow(bool aAction) {
  if (aAction) {
    // unset our flag now that our window has been shown
    mNeedsShow = true;
    auto removeShow = MakeScopeExit([&] { mNeedsShow = false; });

    LOG("nsWindowX11::NativeShow show\n");

    // Set up usertime/startupID metadata for the created window.
    // On X11 we use gtk_window_set_startup_id() so we need to call it
    // before show.
    SetUserTimeAndStartupTokenForActivatedWindow();
    LOG("  calling gtk_widget_show(mShell)\n");
    gtk_widget_show(mShell);

    if (mX11HiddenPopupPositioned) {
      LOG("  re-position hidden popup window [%d, %d]", mClientArea.x,
          mClientArea.y);
      gtk_window_move(GTK_WINDOW(mShell), mClientArea.x, mClientArea.y);
      mX11HiddenPopupPositioned = false;
    }
  } else {
    LOG("nsWindow::NativeShow hide\n");

    // Workaround window freezes on GTK versions before 3.21.2 by
    // ensuring that configure events get dispatched to windows before
    // they are unmapped. See bug 1225044.
    if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
      GtkAllocation allocation;
      gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation);

      GdkEventConfigure event;
      PodZero(&event);
      event.type = GDK_CONFIGURE;
      event.window = mGdkWindow;
      event.send_event = TRUE;
      event.x = allocation.x;
      event.y = allocation.y;
      event.width = allocation.width;
      event.height = allocation.height;

      auto* shellClass = GTK_WIDGET_GET_CLASS(mShell);
      for (unsigned int i = 0; i < mPendingConfigures; i++) {
        (void)shellClass->configure_event(mShell, &event);
      }
      mPendingConfigures = 0;
    }
    gtk_widget_hide(mShell);
  }
}

Messung V0.5 in Prozent
C=91 H=99 G=94

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-09-29) ¤

*© 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.