~unity-team/bamf/0.4

« back to all changes in this revision

Viewing changes to src/bamf-matcher.c

  • Committer: Tarmac
  • Author(s): Marco Trevisan (Treviño)
  • Date: 2012-05-22 16:40:12 UTC
  • mfrom: (457.3.10 better-wmclass-filter)
  • Revision ID: tarmac-20120522164012-ld5k0vg0wfwdcii1
BamfMatcher: use both instance and class names for matching WMClass

Also, filter out the .desktop files that have a defined StartupWMClass
that doesn't match with our .desktop file.. Fixes: https://bugs.launchpad.net/bugs/692462. Approved by Jason Smith.

Show diffs side-by-side

added added

removed removed

Lines of Context:
659
659
}
660
660
 
661
661
static gboolean
662
 
exec_string_should_be_processed (BamfMatcher *self,
663
 
                                 char *exec)
 
662
exec_string_should_be_processed (const char *exec)
664
663
{
 
664
  if (!exec)
 
665
    return TRUE;
 
666
 
665
667
  return !g_str_has_prefix (exec, "ooffice") && !g_str_has_prefix (exec, "libreoffice");
666
668
}
667
669
 
829
831
      return;
830
832
    }
831
833
 
832
 
  if (exec_string_should_be_processed (self, exec))
 
834
  if (exec_string_should_be_processed (exec))
833
835
    {
834
836
      /**
835
837
       * Set of nasty hacks which should be removed some day. We wish to keep the full exec
939
941
      gchar **parts = g_strsplit (line, "\t", 3);
940
942
      exec = parts[1];
941
943
 
942
 
      if (exec_string_should_be_processed (self, exec))
 
944
      if (exec_string_should_be_processed (exec))
943
945
        {
944
946
          char *tmp = trim_exec_string (self, exec);
945
947
          g_free (parts[1]);
1377
1379
{
1378
1380
  const char *class_name = bamf_legacy_window_get_class_name (window);
1379
1381
 
 
1382
  if (!class_name)
 
1383
    return FALSE;
 
1384
 
1380
1385
  return (g_str_has_prefix (class_name, "LibreOffice") ||
1381
1386
          g_str_has_prefix (class_name, "libreoffice") ||
1382
1387
          g_str_has_prefix (class_name, "OpenOffice") ||
1543
1548
 
1544
1549
  gboolean valid_app = FALSE;
1545
1550
 
1546
 
  if (g_strcmp0 (window_class, "Google-chrome") == 0 &&
1547
 
      g_strcmp0 (instance_name, "google-chrome") != 0 &&
1548
 
      !g_str_has_prefix (instance_name, "Google-chrome"))
1549
 
    {
1550
 
      valid_app = TRUE;
1551
 
    }
1552
 
  else if (g_strcmp0 (window_class, "Chromium-browser") == 0 &&
1553
 
           g_strcmp0 (instance_name, "chromium-browser") != 0 &&
1554
 
           !g_str_has_prefix (instance_name, "Chromium-browser"))
1555
 
    {
1556
 
      valid_app = TRUE;
 
1551
  if (instance_name && window_class)
 
1552
    {
 
1553
      if (g_strcmp0 (window_class, "Google-chrome") == 0 &&
 
1554
          g_strcmp0 (instance_name, "google-chrome") != 0 &&
 
1555
          !g_str_has_prefix (instance_name, "Google-chrome"))
 
1556
        {
 
1557
          valid_app = TRUE;
 
1558
        }
 
1559
      else if (g_strcmp0 (window_class, "Chromium-browser") == 0 &&
 
1560
               g_strcmp0 (instance_name, "chromium-browser") != 0 &&
 
1561
               !g_str_has_prefix (instance_name, "Chromium-browser"))
 
1562
        {
 
1563
          valid_app = TRUE;
 
1564
        }
1557
1565
    }
1558
1566
 
1559
1567
  return valid_app;
1620
1628
 
1621
1629
static GList *
1622
1630
bamf_matcher_possible_applications_for_window (BamfMatcher *self,
1623
 
                                               BamfWindow *bamf_window)
 
1631
                                               BamfWindow *bamf_window,
 
1632
                                               const char **target_class_out)
1624
1633
{
1625
1634
  BamfMatcherPrivate *priv;
1626
1635
  BamfLegacyWindow *window;
1627
1636
  GList *desktop_files = NULL, *l;
1628
1637
  char *desktop_file = NULL;
1629
 
  char *desktop_class = NULL;
 
1638
  const char *desktop_class = NULL;
 
1639
  const char *class_name = NULL;
 
1640
  const char *instance_name = NULL;
 
1641
  const char *target_class = NULL;
 
1642
  gboolean filter_by_wmclass = FALSE;
1630
1643
 
1631
1644
  g_return_val_if_fail (BAMF_IS_WINDOW (bamf_window), NULL);
1632
1645
  g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
1633
1646
 
1634
1647
  priv = self->priv;
1635
1648
  window = bamf_window_get_window (bamf_window);
1636
 
 
1637
1649
  desktop_file = get_window_hint (window, _NET_WM_DESKTOP_FILE);
1638
 
 
1639
 
  const char *class_name = bamf_legacy_window_get_class_name (window);
1640
 
  const char *instance_name = bamf_legacy_window_get_class_instance_name (window);
1641
 
  gboolean known_desktop_class = bamf_matcher_has_instance_class_desktop_file (self, instance_name);
1642
 
 
1643
 
  if (!known_desktop_class)
 
1650
  class_name = bamf_legacy_window_get_class_name (window);
 
1651
  instance_name = bamf_legacy_window_get_class_instance_name (window);
 
1652
 
 
1653
  target_class = instance_name;
 
1654
  filter_by_wmclass = bamf_matcher_has_instance_class_desktop_file (self, target_class);
 
1655
 
 
1656
  if (!filter_by_wmclass)
1644
1657
  {
1645
 
    known_desktop_class = is_web_app_window (self, window);
 
1658
    if (is_web_app_window (self, window))
 
1659
      {
 
1660
        // This ensures that a new application is created even for unknown webapps
 
1661
        filter_by_wmclass = TRUE;
 
1662
      }
 
1663
    else
 
1664
      {
 
1665
        target_class = class_name;
 
1666
        filter_by_wmclass = bamf_matcher_has_instance_class_desktop_file (self, target_class);
 
1667
      }
1646
1668
  }
1647
1669
 
1648
1670
  if (desktop_file)
1649
1671
    {
1650
 
      desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
 
1672
      desktop_class = bamf_matcher_get_desktop_file_class (self, desktop_file);
1651
1673
 
1652
 
      if (!known_desktop_class || g_strcmp0 (desktop_class, instance_name) == 0)
 
1674
      if ((!filter_by_wmclass && !desktop_class) || g_strcmp0 (desktop_class, target_class) == 0)
1653
1675
        {
1654
1676
          desktop_files = g_list_prepend (desktop_files, desktop_file);
1655
1677
        }
1675
1697
 
1676
1698
              if (desktop_file)
1677
1699
                {
1678
 
                  desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
 
1700
                  desktop_class = bamf_matcher_get_desktop_file_class (self, desktop_file);
1679
1701
 
1680
 
                  if (!known_desktop_class || g_strcmp0 (desktop_class, instance_name) == 0)
 
1702
                  if ((!filter_by_wmclass && !desktop_class) || g_strcmp0 (desktop_class, target_class) == 0)
1681
1703
                    {
1682
1704
                      if (!g_list_find_custom (desktop_files, desktop_file,
1683
1705
                                               (GCompareFunc) g_strcmp0))
1708
1730
            {
1709
1731
              gboolean append = FALSE;
1710
1732
 
1711
 
              if (instance_name)
 
1733
              if (target_class)
1712
1734
                {
1713
 
                  desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
1714
 
                  if (!known_desktop_class || g_strcmp0 (desktop_class, instance_name) == 0)
 
1735
                  desktop_class = bamf_matcher_get_desktop_file_class (self, desktop_file);
 
1736
                  if ((!filter_by_wmclass && !desktop_class) || g_strcmp0 (desktop_class, target_class) == 0)
1715
1737
                    {
1716
1738
                      append = TRUE;
1717
1739
                    }
1753
1775
      g_list_free (pid_list);
1754
1776
    }
1755
1777
 
1756
 
  if (!desktop_files && known_desktop_class)
1757
 
    {
1758
 
      desktop_files = bamf_matcher_get_class_matching_desktop_files (self, instance_name);
 
1778
  if (!desktop_files && filter_by_wmclass)
 
1779
    {
 
1780
      desktop_files = bamf_matcher_get_class_matching_desktop_files (self, target_class);
 
1781
    }
 
1782
 
 
1783
  if (target_class_out)
 
1784
    {
 
1785
      *target_class_out = target_class;
1759
1786
    }
1760
1787
 
1761
1788
  return desktop_files;
1762
1789
}
1763
1790
 
1764
 
static void
1765
 
bamf_matcher_setup_window_state (BamfMatcher *self,
1766
 
                                 BamfWindow *bamf_window)
 
1791
static BamfApplication *
 
1792
bamf_matcher_get_application_for_window (BamfMatcher *self,
 
1793
                                         BamfWindow *bamf_window,
 
1794
                                         gboolean *new_application)
1767
1795
{
1768
1796
  GList *possible_apps, *l;
1769
1797
  BamfLegacyWindow *window;
1770
 
  const gchar *app_class;
 
1798
  const gchar *win_class_name;
 
1799
  const gchar *target_class = NULL;
 
1800
  const gchar *app_class = NULL;
1771
1801
  const gchar *app_desktop = NULL;
1772
1802
  BamfApplication *app = NULL, *best = NULL;
1773
1803
 
1774
 
  g_return_if_fail (BAMF_IS_MATCHER (self));
1775
 
  g_return_if_fail (BAMF_IS_WINDOW (bamf_window));
 
1804
  g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
 
1805
  g_return_val_if_fail (BAMF_IS_WINDOW (bamf_window), NULL);
1776
1806
 
1777
1807
  window = bamf_window_get_window (bamf_window);
1778
 
 
1779
 
  possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window);
1780
 
  const char *win_instance = bamf_legacy_window_get_class_instance_name (window);
1781
 
  const char *win_class_name = bamf_legacy_window_get_class_name (window);
1782
 
 
1783
 
  app_class = win_instance;
 
1808
  win_class_name = bamf_legacy_window_get_class_name (window);
 
1809
 
 
1810
  possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window, &target_class);
 
1811
  app_class = target_class;
1784
1812
 
1785
1813
  /* Loop over every possible desktop file that could match the window, and try
1786
1814
   * to reuse an already-opened window that uses it.
1799
1827
              const gchar *app_desktop_class;
1800
1828
              app_desktop_class = bamf_application_get_wmclass (app);
1801
1829
 
1802
 
              if (win_instance && app_desktop_class && strcasecmp (win_instance, app_desktop_class) == 0)
 
1830
              if (target_class && app_desktop_class && strcasecmp (target_class, app_desktop_class) == 0)
1803
1831
                {
1804
1832
                  best = app;
1805
1833
                  break;
1829
1857
              const gchar *best_desktop_class;
1830
1858
 
1831
1859
              best_app_class = bamf_application_get_wmclass (best);
1832
 
              best_desktop_class = g_hash_table_lookup (self->priv->desktop_class_table, best_desktop);
 
1860
              best_desktop_class = bamf_matcher_get_desktop_file_class (self, best_desktop);
1833
1861
 
1834
1862
              /* We compare the two classes using their "distance" from the
1835
1863
               * desidered class value */
1867
1895
 
1868
1896
          if (bamf_application_contains_similar_to_window (app, bamf_window))
1869
1897
            {
1870
 
              if (win_instance && g_strcmp0 (win_instance, app_desktop_class) == 0)
 
1898
              if (target_class && g_strcmp0 (target_class, app_desktop_class) == 0)
1871
1899
                {
1872
1900
                  best = app;
1873
1901
                  break;
1896
1924
        }
1897
1925
 
1898
1926
      bamf_application_set_wmclass (best, app_class);
1899
 
      bamf_matcher_register_view_stealing_ref (self, BAMF_VIEW (best));
1900
 
    }
1901
1927
 
1902
 
  bamf_view_add_child (BAMF_VIEW (best), BAMF_VIEW (bamf_window));
 
1928
      if (new_application)
 
1929
        *new_application = TRUE;
 
1930
    }
 
1931
  else
 
1932
    {
 
1933
      if (new_application)
 
1934
        *new_application = FALSE;
 
1935
    }
1903
1936
 
1904
1937
  g_list_free_full (possible_apps, g_free);
 
1938
 
 
1939
  return best;
1905
1940
}
1906
1941
 
1907
1942
/* Ensures that the window hint is set if a registered pid matches, and that set window hints
1972
2007
handle_raw_window (BamfMatcher *self, BamfLegacyWindow *window)
1973
2008
{
1974
2009
  BamfWindow *bamfwindow;
 
2010
  BamfApplication *bamfapplication;
1975
2011
 
1976
2012
  g_return_if_fail (BAMF_IS_MATCHER (self));
1977
2013
  g_return_if_fail (BAMF_IS_LEGACY_WINDOW (window));
1989
2025
  bamfwindow = bamf_window_new (window);
1990
2026
  bamf_matcher_register_view_stealing_ref (self, BAMF_VIEW (bamfwindow));
1991
2027
 
1992
 
  bamf_matcher_setup_window_state (self, bamfwindow);
 
2028
  gboolean new_app = FALSE;
 
2029
  bamfapplication = bamf_matcher_get_application_for_window (self, bamfwindow, &new_app);
 
2030
 
 
2031
  if (new_app)
 
2032
    {
 
2033
      bamf_matcher_register_view_stealing_ref (self, BAMF_VIEW (bamfapplication));
 
2034
    }
 
2035
 
 
2036
  bamf_view_add_child (BAMF_VIEW (bamfapplication), BAMF_VIEW (bamfwindow));
1993
2037
}
1994
2038
 
1995
2039
static void
2243
2287
    }
2244
2288
}
2245
2289
 
 
2290
const char *
 
2291
bamf_matcher_get_desktop_file_class (BamfMatcher * self, const char * desktop_file)
 
2292
{
 
2293
  g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
 
2294
  g_return_val_if_fail (desktop_file, NULL);
 
2295
 
 
2296
  return g_hash_table_lookup (self->priv->desktop_class_table, desktop_file);
 
2297
}
 
2298
 
2246
2299
static int
2247
2300
x_error_handler (Display *display, XErrorEvent *event)
2248
2301
{
2347
2400
  return (idx_a < idx_b) ? -1 : 1;
2348
2401
}
2349
2402
 
2350
 
 
2351
2403
GVariant *
2352
2404
bamf_matcher_get_window_stack_for_monitor (BamfMatcher *matcher, gint monitor)
2353
2405
{
2515
2567
      if (g_list_find_custom (priv->favorites, fav, (GCompareFunc) g_strcmp0))
2516
2568
        continue;
2517
2569
 
 
2570
      bamf_matcher_load_desktop_file (matcher, fav);
2518
2571
      priv->favorites = g_list_prepend (priv->favorites, g_strdup (fav));
2519
 
      bamf_matcher_load_desktop_file (matcher, fav);
2520
2572
    }
2521
2573
 
2522
2574
  g_signal_emit (matcher, matcher_signals[FAVORITES_CHANGED], 0);