# Global Metrics

path: .metrics.nom.total
old: 4.0
new: 24.0
path: .metrics.nom.closures
old: 0.0
new: 1.0
path: .metrics.nom.functions
old: 4.0
new: 23.0
path: .metrics.cognitive.sum
old: 25.0
new: 34.0
path: .metrics.cognitive.average
old: 6.25
new: 1.4166666666666667
path: .metrics.loc.cloc
old: 14.0
new: 25.0
path: .metrics.loc.blank
old: 11.0
new: 40.0
path: .metrics.loc.lloc
old: 131.0
new: 99.0
path: .metrics.loc.sloc
old: 216.0
new: 309.0
path: .metrics.loc.ploc
old: 191.0
new: 244.0
path: .metrics.cyclomatic.sum
old: 20.0
new: 74.0
path: .metrics.cyclomatic.average
old: 4.0
new: 1.85
path: .metrics.mi.mi_original
old: 32.457596476657315
new: 14.07711662305698
path: .metrics.mi.mi_visual_studio
old: 18.98105057114463
new: 8.232231943308177
path: .metrics.mi.mi_sei
old: -7.625079719829888
new: -26.53070306427765
path: .metrics.nexits.average
old: 0.25
new: 0.5416666666666666
path: .metrics.nexits.sum
old: 1.0
new: 13.0
path: .metrics.halstead.bugs
old: 1.4952760982485858
new: 1.5692946079751275
path: .metrics.halstead.level
old: 0.02729852005214324
new: 0.026182782334907617
path: .metrics.halstead.N2
old: 483.0
new: 447.0
path: .metrics.halstead.effort
old: 300444.2999329516
new: 323026.8377124963
path: .metrics.halstead.n2
old: 178.0
new: 158.0
path: .metrics.halstead.length
old: 1068.0
new: 1123.0
path: .metrics.halstead.purity_ratio
old: 1.3661634019386073
new: 1.1419228145773783
path: .metrics.halstead.estimated_program_length
old: 1459.0625132704326
new: 1282.379320770396
path: .metrics.halstead.vocabulary
old: 205.0
new: 185.0
path: .metrics.halstead.volume
old: 8201.684746271816
new: 8457.741380159818
path: .metrics.halstead.N1
old: 585.0
new: 676.0
path: .metrics.halstead.time
old: 16691.349996275087
new: 17945.935428472018
path: .metrics.halstead.difficulty
old: 36.63202247191011
new: 38.19303797468354
path: .metrics.nargs.sum
old: 17.0
new: 23.0
path: .metrics.nargs.average
old: 4.25
new: 0.9583333333333334

# Spaces Data

## Minimal test - lines (15, 309)

path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 13.0
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 0.5416666666666666
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 16.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 40.0
path: .spaces[0].metrics.loc.lloc
old: 47.0
new: 99.0
path: .spaces[0].metrics.loc.ploc
old: 53.0
new: 239.0
path: .spaces[0].metrics.loc.sloc
old: 53.0
new: 295.0
path: .spaces[0].metrics.halstead.N2
old: 128.0
new: 442.0
path: .spaces[0].metrics.halstead.bugs
old: 0.2990260422869985
new: 1.5810387743387826
path: .spaces[0].metrics.halstead.N1
old: 142.0
new: 676.0
path: .spaces[0].metrics.halstead.effort
old: 26868.62248334136
new: 326659.77870616654
path: .spaces[0].metrics.halstead.n2
old: 55.0
new: 153.0
path: .spaces[0].metrics.halstead.time
old: 1492.70124907452
new: 18147.765483675917
path: .spaces[0].metrics.halstead.n1
old: 14.0
new: 27.0
path: .spaces[0].metrics.halstead.volume
old: 1649.3016033301058
new: 8375.891761696577
path: .spaces[0].metrics.halstead.difficulty
old: 16.29090909090909
new: 39.0
path: .spaces[0].metrics.halstead.length
old: 270.0
new: 1118.0
path: .spaces[0].metrics.halstead.vocabulary
old: 69.0
new: 180.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 371.27775315266274
new: 1238.7623024903896
path: .spaces[0].metrics.halstead.level
old: 0.061383928571428575
new: 0.02564102564102564
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.3751027894543064
new: 1.1080163707427455
path: .spaces[0].metrics.mi.mi_visual_studio
old: 39.59012486914212
new: 8.835562872000953
path: .spaces[0].metrics.mi.mi_original
old: 67.69911352623303
new: 15.108812511121627
path: .spaces[0].metrics.mi.mi_sei
old: 22.171963083671542
new: -28.81991491261285
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 34.0
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 1.4166666666666667
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 24.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 23.0
path: .spaces[0].metrics.nargs.average
old: 5.0
new: 0.9583333333333334
path: .spaces[0].metrics.nargs.sum
old: 5.0
new: 23.0
path: .spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 73.0
path: .spaces[0].metrics.cyclomatic.average
old: 2.0
new: 1.871794871794872

### Code

    namespace mozilla {
    namespace widget {

    // nsWaylandDisplay needs to be created for each calling thread(main thread,
    // compositor thread and render thread)
    #define MAX_DISPLAY_CONNECTIONS 10

    // An array of active wayland displays. We need a display for every thread
    // where is wayland interface used as we need to dispatch waylands events
    // there.
    static RefPtr gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
    static StaticMutex gWaylandDisplayArrayWriteMutex;

    // Dispatch events to Compositor/Render queues
    void WaylandDispatchDisplays() {
      MOZ_ASSERT(NS_IsMainThread(),
                 "WaylandDispatchDisplays() is supposed to run in main thread");
      for (auto& display : gWaylandDisplays) {
        if (display) {
          display->DispatchEventQueue();
        }
      }
    }

    void WaylandDisplayRelease() {
      StaticMutexAutoLock lock(gWaylandDisplayArrayWriteMutex);
      for (auto& display : gWaylandDisplays) {
        if (display) {
          display = nullptr;
        }
      }
    }

    // Get WaylandDisplay for given wl_display and actual calling thread.
    RefPtr WaylandDisplayGet(GdkDisplay* aGdkDisplay) {
      wl_display* waylandDisplay = WaylandDisplayGetWLDisplay(aGdkDisplay);
      if (!waylandDisplay) {
        return nullptr;
      }

      // Search existing display connections for wl_display:thread combination.
      for (auto& display : gWaylandDisplays) {
        if (display && display->Matches(waylandDisplay)) {
          return display;
        }
      }

      StaticMutexAutoLock arrayLock(gWaylandDisplayArrayWriteMutex);
      for (auto& display : gWaylandDisplays) {
        if (display == nullptr) {
          display = new nsWaylandDisplay(waylandDisplay);
          return display;
        }
      }

      MOZ_CRASH("There's too many wayland display conections!");
      return nullptr;
    }

    wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay) {
      if (!aGdkDisplay) {
        aGdkDisplay = gdk_display_get_default();
        if (!aGdkDisplay || GDK_IS_X11_DISPLAY(aGdkDisplay)) {
          return nullptr;
        }
      }

      return gdk_wayland_display_get_wl_display(aGdkDisplay);
    }

    void nsWaylandDisplay::SetShm(wl_shm* aShm) { mShm = aShm; }

    void nsWaylandDisplay::SetCompositor(wl_compositor* aCompositor) {
      mCompositor = aCompositor;
    }

    void nsWaylandDisplay::SetSubcompositor(wl_subcompositor* aSubcompositor) {
      mSubcompositor = aSubcompositor;
    }

    void nsWaylandDisplay::SetDataDeviceManager(
        wl_data_device_manager* aDataDeviceManager) {
      mDataDeviceManager = aDataDeviceManager;
    }

    void nsWaylandDisplay::SetSeat(wl_seat* aSeat) { mSeat = aSeat; }

    void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
        gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager) {
      mPrimarySelectionDeviceManagerGtk = aPrimarySelectionDeviceManager;
    }

    void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
        zwp_primary_selection_device_manager_v1* aPrimarySelectionDeviceManager) {
      mPrimarySelectionDeviceManagerZwpV1 = aPrimarySelectionDeviceManager;
    }

    void nsWaylandDisplay::SetIdleInhibitManager(
        zwp_idle_inhibit_manager_v1* aIdleInhibitManager) {
      mIdleInhibitManager = aIdleInhibitManager;
    }

    static void global_registry_handler(void* data, wl_registry* registry,
                                        uint32_t id, const char* interface,
                                        uint32_t version) {
      auto* display = static_cast(data);
      if (!display) {
        return;
      }

      if (strcmp(interface, "wl_shm") == 0) {
        auto* shm = WaylandRegistryBind(registry, id, &wl_shm_interface, 1);
        wl_proxy_set_queue((struct wl_proxy*)shm, display->GetEventQueue());
        display->SetShm(shm);
      } else if (strcmp(interface, "wl_data_device_manager") == 0) {
        int data_device_manager_version = MIN(version, 3);
        auto* data_device_manager = WaylandRegistryBind(
            registry, id, &wl_data_device_manager_interface,
            data_device_manager_version);
        wl_proxy_set_queue((struct wl_proxy*)data_device_manager,
                           display->GetEventQueue());
        display->SetDataDeviceManager(data_device_manager);
      } else if (strcmp(interface, "wl_seat") == 0) {
        auto* seat =
            WaylandRegistryBind(registry, id, &wl_seat_interface, 1);
        wl_proxy_set_queue((struct wl_proxy*)seat, display->GetEventQueue());
        display->SetSeat(seat);
      } else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
        auto* primary_selection_device_manager =
            WaylandRegistryBind(
                registry, id, >k_primary_selection_device_manager_interface, 1);
        wl_proxy_set_queue((struct wl_proxy*)primary_selection_device_manager,
                           display->GetEventQueue());
        display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
      } else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") ==
                 0) {
        auto* primary_selection_device_manager =
            WaylandRegistryBind(
                registry, id, &zwp_primary_selection_device_manager_v1_interface,
                1);
        wl_proxy_set_queue((struct wl_proxy*)primary_selection_device_manager,
                           display->GetEventQueue());
        display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
      } else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) {
        auto* idle_inhibit_manager =
            WaylandRegistryBind(
                registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
        wl_proxy_set_queue((struct wl_proxy*)idle_inhibit_manager,
                           display->GetEventQueue());
        display->SetIdleInhibitManager(idle_inhibit_manager);
      } else if (strcmp(interface, "wl_compositor") == 0) {
        // Requested wl_compositor version 4 as we need wl_surface_damage_buffer().
        auto* compositor = WaylandRegistryBind(
            registry, id, &wl_compositor_interface, 4);
        wl_proxy_set_queue((struct wl_proxy*)compositor, display->GetEventQueue());
        display->SetCompositor(compositor);
      } else if (strcmp(interface, "wl_subcompositor") == 0) {
        auto* subcompositor = WaylandRegistryBind(
            registry, id, &wl_subcompositor_interface, 1);
        wl_proxy_set_queue((struct wl_proxy*)subcompositor,
                           display->GetEventQueue());
        display->SetSubcompositor(subcompositor);
      }
    }

    static void global_registry_remover(void* data, wl_registry* registry,
                                        uint32_t id) {}

    static const struct wl_registry_listener registry_listener = {
        global_registry_handler, global_registry_remover};

    bool nsWaylandDisplay::DispatchEventQueue() {
      if (mEventQueue) {
        wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
      }
      return true;
    }

    void nsWaylandDisplay::SyncEnd() {
      wl_callback_destroy(mSyncCallback);
      mSyncCallback = nullptr;
    }

    static void wayland_sync_callback(void* data, struct wl_callback* callback,
                                      uint32_t time) {
      auto display = static_cast(data);
      display->SyncEnd();
    }

    static const struct wl_callback_listener sync_callback_listener = {
        .done = wayland_sync_callback};

    void nsWaylandDisplay::SyncBegin() {
      WaitForSyncEnd();

      // Use wl_display_sync() to synchronize wayland events.
      // See dri2_wl_swap_buffers_with_damage() from MESA
      // or wl_display_roundtrip_queue() from wayland-client.
      struct wl_display* displayWrapper =
          static_cast(wl_proxy_create_wrapper((void*)mDisplay));
      if (!displayWrapper) {
        NS_WARNING("Failed to create wl_proxy wrapper!");
        return;
      }

      wl_proxy_set_queue((struct wl_proxy*)displayWrapper, mEventQueue);
      mSyncCallback = wl_display_sync(displayWrapper);
      wl_proxy_wrapper_destroy((void*)displayWrapper);

      if (!mSyncCallback) {
        NS_WARNING("Failed to create wl_display_sync callback!");
        return;
      }

      wl_callback_add_listener(mSyncCallback, &sync_callback_listener, this);
      wl_display_flush(mDisplay);
    }

    void nsWaylandDisplay::QueueSyncBegin() {
      RefPtr self(this);
      NS_DispatchToMainThread(
          NS_NewRunnableFunction("nsWaylandDisplay::QueueSyncBegin",
                                 [self]() -> void { self->SyncBegin(); }));
    }

    void nsWaylandDisplay::WaitForSyncEnd() {
      // We're done here
      if (!mSyncCallback) {
        return;
      }

      while (mSyncCallback != nullptr) {
        // TODO: wl_display_dispatch_queue() should not be called while
        // glib main loop is iterated at nsAppShell::ProcessNextNativeEvent().
        if (wl_display_dispatch_queue(mDisplay, mEventQueue) == -1) {
          NS_WARNING("wl_display_dispatch_queue failed!");
          SyncEnd();
          return;
        }
      }
    }

    bool nsWaylandDisplay::Matches(wl_display* aDisplay) {
      return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
    }

    nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay, bool aLighWrapper)
        : mThreadId(PR_GetCurrentThread()),
          mDisplay(aDisplay),
          mEventQueue(nullptr),
          mDataDeviceManager(nullptr),
          mCompositor(nullptr),
          mSubcompositor(nullptr),
          mSeat(nullptr),
          mShm(nullptr),
          mSyncCallback(nullptr),
          mPrimarySelectionDeviceManagerGtk(nullptr),
          mPrimarySelectionDeviceManagerZwpV1(nullptr),
          mIdleInhibitManager(nullptr),
          mRegistry(nullptr),
          mExplicitSync(false) {
      if (!aLighWrapper) {
        mRegistry = wl_display_get_registry(mDisplay);
        wl_registry_add_listener(mRegistry, ®istry_listener, this);
      }

      if (!NS_IsMainThread()) {
        mEventQueue = wl_display_create_queue(mDisplay);
        wl_proxy_set_queue((struct wl_proxy*)mRegistry, mEventQueue);
      }

      if (!aLighWrapper) {
        if (mEventQueue) {
          wl_display_roundtrip_queue(mDisplay, mEventQueue);
          wl_display_roundtrip_queue(mDisplay, mEventQueue);
        } else {
          wl_display_roundtrip(mDisplay);
          wl_display_roundtrip(mDisplay);
        }
      }
    }

    nsWaylandDisplay::~nsWaylandDisplay() {
      wl_registry_destroy(mRegistry);
      mRegistry = nullptr;

      if (mEventQueue) {
        wl_event_queue_destroy(mEventQueue);
        mEventQueue = nullptr;
      }
      mDisplay = nullptr;
    }

    }  // namespace widget
    }  // namespace mozilla