~ubuntu-branches/ubuntu/precise/bamf/precise

« back to all changes in this revision

Viewing changes to src/bamf-matcher.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-04-01 11:17:17 UTC
  • mfrom: (1.1.29 upstream)
  • Revision ID: james.westby@ubuntu.com-20110401111717-bfvq7468f7okxmjb
Tags: 0.2.82-0ubuntu1
* New upstream release.
  - bamfdaemon crashed with SIGSEGV in XInternAtom() (LP: #743407)
  - catch more cases for 'Keep in Launcher' by recognizing StatupWMClass
    from .desktop file (LP: #693231)

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 *
18
18
 */
19
19
 
 
20
#include <gdk/gdkx.h>
20
21
 
21
22
#include "bamf-marshal.h"
22
23
#include "bamf-matcher.h"
61
62
  GArray          * known_pids;
62
63
  GHashTable      * desktop_id_table;
63
64
  GHashTable      * desktop_file_table;
 
65
  GHashTable      * desktop_class_table;
64
66
  GHashTable      * exec_list;
65
67
  GHashTable      * registered_pids;
66
68
  GList           * views;
416
418
      file_list = g_list_append (file_list, datadup);
417
419
      id_list   = g_list_append (id_list,   datadup);
418
420
    }
419
 
      
 
421
 
420
422
  g_hash_table_insert (desktop_file_table, g_strdup (exec),       file_list);
421
423
  g_hash_table_insert (desktop_id_table,   g_strdup (desktop_id), id_list);
422
 
 
 
424
}
 
425
 
 
426
static void
 
427
insert_desktop_file_class_into_table (BamfMatcher *self,
 
428
                                      const char *desktop_file,
 
429
                                      GHashTable *desktop_class_table)
 
430
{
 
431
  GKeyFile *desktop_keyfile;
 
432
  char *class;
 
433
 
 
434
  g_return_if_fail (desktop_file);
 
435
 
 
436
  desktop_keyfile = g_key_file_new ();
 
437
 
 
438
  if (g_key_file_load_from_file (desktop_keyfile, desktop_file, G_KEY_FILE_NONE,
 
439
                                 NULL))
 
440
    {
 
441
      class = g_key_file_get_string (desktop_keyfile,
 
442
                                     G_KEY_FILE_DESKTOP_GROUP,
 
443
                                     G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS,
 
444
                                     NULL);
 
445
      if (class)
 
446
        g_hash_table_insert (desktop_class_table, g_strdup (desktop_file), class);
 
447
 
 
448
      g_key_file_free (desktop_keyfile);
 
449
    }
423
450
}
424
451
 
425
452
static void
426
453
load_desktop_file_to_table (BamfMatcher * self,
427
454
                            const char *file,
428
455
                            GHashTable *desktop_file_table,
429
 
                            GHashTable *desktop_id_table)
 
456
                            GHashTable *desktop_id_table,
 
457
                            GHashTable *desktop_class_table)
430
458
{
431
459
  GAppInfo *desktop_file;
432
460
  char *exec;
467
495
  desktop_id = g_string_truncate (desktop_id, desktop_id->len - 8); /* remove last 8 characters for .desktop */
468
496
  
469
497
  insert_data_into_tables (self, file, exec, desktop_id->str, desktop_file_table, desktop_id_table);
 
498
  insert_desktop_file_class_into_table (self, file, desktop_class_table);
470
499
 
471
500
  g_free (exec);
472
501
  g_string_free (desktop_id, TRUE);
476
505
load_directory_to_table (BamfMatcher * self,
477
506
                         const char *directory,
478
507
                         GHashTable *desktop_file_table,
479
 
                         GHashTable *desktop_id_table)
 
508
                         GHashTable *desktop_id_table,
 
509
                         GHashTable *desktop_class_table)
480
510
{
481
511
  GFile *dir;
482
512
  GFileEnumerator *enumerator;
506
536
        load_desktop_file_to_table (self,
507
537
                                    path,
508
538
                                    desktop_file_table,
509
 
                                    desktop_id_table);
 
539
                                    desktop_id_table,
 
540
                                    desktop_class_table);
510
541
 
511
542
      g_free ((gpointer) path);
512
543
      g_object_unref (info);
520
551
load_index_file_to_table (BamfMatcher * self,
521
552
                          const char *index_file,
522
553
                          GHashTable *desktop_file_table,
523
 
                          GHashTable *desktop_id_table)
 
554
                          GHashTable *desktop_id_table,
 
555
                          GHashTable *desktop_class_table)
524
556
{
525
557
  GFile *file;
526
558
  GFileInputStream *stream;
569
601
      g_string_truncate (desktop_id, desktop_id->len - 8);
570
602
      
571
603
      insert_data_into_tables (self, filename->str, exec, desktop_id->str, desktop_file_table, desktop_id_table);
 
604
      insert_desktop_file_class_into_table (self, filename->str, desktop_class_table);
572
605
 
573
606
      g_string_free (desktop_id, TRUE);
574
607
      length = 0;
612
645
  if (!g_list_find_custom (dirs, "/usr/local/share/applications", (GCompareFunc) g_strcmp0))
613
646
    dirs = g_list_prepend (dirs, g_strdup ("/usr/local/share/applications"));
614
647
  
615
 
  dirs = g_list_prepend (dirs, g_strdup (g_build_filename (g_get_home_dir (), ".share/applications", NULL)));
 
648
  dirs = g_list_prepend (dirs, g_strdup (g_build_filename (g_get_home_dir (), ".local/share/applications", NULL)));
616
649
  
617
650
  if (data_dirs)
618
651
    g_strfreev (data_dirs);
690
723
    {
691
724
      g_hash_table_foreach_remove (self->priv->desktop_id_table, (GHRFunc) hash_table_remove_values, path);
692
725
      g_hash_table_foreach_remove (self->priv->desktop_file_table, (GHRFunc) hash_table_remove_values, path);
 
726
      g_hash_table_remove (self->priv->desktop_class_table, path);
693
727
    }
694
728
 
695
729
out:
697
731
}
698
732
 
699
733
static void
700
 
create_desktop_file_table (BamfMatcher * self, GHashTable **desktop_file_table, GHashTable **desktop_id_table)
 
734
create_desktop_file_table (BamfMatcher * self,
 
735
                           GHashTable **desktop_file_table,
 
736
                           GHashTable **desktop_id_table,
 
737
                           GHashTable **desktop_class_table)
701
738
{
702
739
  GList *directories;
703
740
  GList *l;
718
755
                           (GDestroyNotify) g_free,
719
756
                           NULL);
720
757
 
 
758
  *desktop_class_table =
 
759
    g_hash_table_new_full ((GHashFunc) g_str_hash,
 
760
                           (GEqualFunc) g_str_equal,
 
761
                           (GDestroyNotify) g_free,
 
762
                           (GDestroyNotify) g_free);
 
763
 
721
764
  g_return_if_fail (BAMF_IS_MATCHER (self));
722
765
 
723
766
  directories = get_desktop_file_directories (self);
740
783
 
741
784
      if (g_file_test (bamf_file, G_FILE_TEST_EXISTS))
742
785
        {
743
 
          load_index_file_to_table (self, bamf_file, *desktop_file_table, *desktop_id_table);
 
786
          load_index_file_to_table (self, bamf_file, *desktop_file_table,
 
787
                                    *desktop_id_table, *desktop_class_table);
744
788
        }
745
789
      else
746
790
        {
747
 
          load_directory_to_table (self, directory, *desktop_file_table, *desktop_id_table);
 
791
          load_directory_to_table (self, directory, *desktop_file_table,
 
792
                                   *desktop_id_table, *desktop_class_table);
748
793
        }
749
794
 
750
795
      g_free (directory);
775
820
  gulong numItems;
776
821
  gulong bytesAfter;
777
822
  unsigned char *buffer;
 
823
  gboolean close_display = TRUE;
778
824
 
779
825
  g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
780
826
  g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (window), NULL);
781
827
  g_return_val_if_fail (atom_name, NULL);
782
828
 
783
829
  XDisplay = XOpenDisplay (NULL);
 
830
  if (!XDisplay)
 
831
  {
 
832
    XDisplay = gdk_x11_get_default_xdisplay ();
 
833
    if (!XDisplay)
 
834
    {
 
835
      g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
 
836
      return hint;
 
837
    }
 
838
    
 
839
    close_display = FALSE;
 
840
  }
 
841
 
784
842
  atom = XInternAtom (XDisplay, atom_name, FALSE);
785
843
 
786
844
  int result = XGetWindowProperty (XDisplay,
796
854
                                   &bytesAfter,
797
855
                                   &buffer);
798
856
 
799
 
  XCloseDisplay (XDisplay);
 
857
  if (close_display)
 
858
    XCloseDisplay (XDisplay);
800
859
 
801
860
  if (result == Success && numItems > 0)
802
861
    {
814
873
                 const char *data)
815
874
{
816
875
  Display *XDisplay;
 
876
  gboolean close_display = TRUE;
817
877
 
818
878
  g_return_if_fail (BAMF_IS_MATCHER (self));
819
879
  g_return_if_fail (BAMF_LEGACY_WINDOW (window));
821
881
  g_return_if_fail (data);
822
882
  
823
883
  XDisplay = XOpenDisplay (NULL);
 
884
  if (!XDisplay)
 
885
  {
 
886
    XDisplay = gdk_x11_get_default_xdisplay ();
 
887
    if (!XDisplay)
 
888
    {
 
889
      g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
 
890
      return;
 
891
    }
 
892
    close_display = FALSE;
 
893
  }
824
894
 
825
895
  XChangeProperty (XDisplay,
826
896
                   bamf_legacy_window_get_xid (window),
832
902
                   PropModeReplace,
833
903
                   (unsigned char *) data,
834
904
                   strlen (data));
 
905
 
 
906
  if (close_display)
835
907
  XCloseDisplay (XDisplay);
836
908
}
837
909
 
993
1065
    }
994
1066
  else
995
1067
    {
996
 
      char *class_name = window_class_name (window);
997
 
 
998
 
      if (class_name)
 
1068
      char *window_class = window_class_name (window);
 
1069
      
 
1070
      char *desktop_file;
 
1071
      char *desktop_class;
 
1072
      
 
1073
      if (window_class)
999
1074
        {
1000
 
          class_name = g_ascii_strdown (class_name, -1);
1001
 
          l = g_hash_table_lookup (priv->desktop_id_table, class_name);
 
1075
          char *window_class_down = g_ascii_strdown (g_strdup(window_class), -1);
 
1076
          l = g_hash_table_lookup (priv->desktop_id_table, window_class_down);
 
1077
          g_free (window_class_down);
1002
1078
 
1003
1079
          for (; l; l = l->next)
1004
1080
            {
1005
 
              if (l->data && !g_list_find_custom (desktop_files, l->data, (GCompareFunc) g_strcmp0))
1006
 
                desktop_files = g_list_prepend (desktop_files, g_strdup (l->data));
1007
 
            }
1008
 
 
1009
 
         desktop_files = g_list_reverse (desktop_files);
1010
 
         g_free (class_name);
1011
 
       }
 
1081
              desktop_file = l->data;
 
1082
              if (desktop_file)
 
1083
                {
 
1084
                  desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
 
1085
                  if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) &&
 
1086
                      !g_list_find_custom (desktop_files, desktop_file,
 
1087
                                           (GCompareFunc) g_strcmp0))
 
1088
                    {
 
1089
                      desktop_files = g_list_prepend (desktop_files, g_strdup (desktop_file));
 
1090
                    }
 
1091
                }
 
1092
            }
 
1093
 
 
1094
          desktop_files = g_list_reverse (desktop_files);
 
1095
        }
 
1096
 
 
1097
      /* Iterate over the desktop class table, and add matching desktop files */
 
1098
      gpointer key;
 
1099
      gpointer value;
 
1100
      GHashTableIter iter;
 
1101
      g_hash_table_iter_init (&iter, priv->desktop_class_table);
 
1102
 
 
1103
      while (g_hash_table_iter_next (&iter, &key, &value))
 
1104
        {
 
1105
          desktop_file = g_strdup (key);
 
1106
          desktop_class = value;
 
1107
          if (g_strcmp0 (desktop_class, window_class) == 0 &&
 
1108
              !g_list_find_custom (desktop_files, desktop_file, (GCompareFunc) g_strcmp0))
 
1109
            {
 
1110
              desktop_files = g_list_prepend (desktop_files, desktop_file);
 
1111
            }
 
1112
        }
1012
1113
 
1013
1114
      pid = bamf_legacy_window_get_pid (window);
1014
 
      
1015
1115
      pid_list = bamf_matcher_possible_applications_for_pid (self, pid);
1016
1116
      
1017
 
      /* Append these files to the end to give preference to class_name style picking.
 
1117
      /* Append these files to the end to give preference to window_class style picking.
1018
1118
         This style of matching is prefered and used by GNOME Shell however does not work
1019
1119
         very well in practice, thus requiring the fallback here */
1020
1120
      for (l = pid_list; l; l = l->next)
1021
1121
        {
 
1122
          desktop_file = l->data;
1022
1123
          if (g_list_find_custom (desktop_files, l->data, (GCompareFunc) g_strcmp0))
1023
 
            g_free (l->data);
 
1124
            g_free (desktop_file);
1024
1125
          else
1025
 
            desktop_files = g_list_append (desktop_files, l->data);
 
1126
            {
 
1127
              if (window_class)
 
1128
                {
 
1129
                  desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
 
1130
                  if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) &&
 
1131
                      !g_list_find_custom (desktop_files, desktop_file,
 
1132
                                           (GCompareFunc) g_strcmp0))
 
1133
                    {
 
1134
                      desktop_files = g_list_append (desktop_files, desktop_file);
 
1135
                    }
 
1136
                }
 
1137
              else
 
1138
                desktop_files = g_list_append (desktop_files, desktop_file);
 
1139
            }
1026
1140
        }
1027
 
      
 
1141
 
 
1142
      g_free (window_class);
1028
1143
      g_list_free (pid_list);
1029
1144
    }
1030
1145
  
1039
1154
  BamfLegacyWindow *window;
1040
1155
  GList *views, *a;
1041
1156
  char *desktop_file;
 
1157
  char *win_class;
 
1158
  char *app_class;
1042
1159
  BamfApplication *app = NULL, *best = NULL;
1043
1160
  BamfView *view;
1044
1161
 
1049
1166
  views = self->priv->views;
1050
1167
 
1051
1168
  possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window);
 
1169
  win_class = window_class_name(window);
1052
1170
 
1053
1171
  /* Loop over every application, inside that application see if its .desktop file
1054
1172
   * matches with any of our possible hits. If so we match it. If we have no possible hits
1062
1180
        continue;
1063
1181
 
1064
1182
      app = BAMF_APPLICATION (view);
 
1183
      app_class = bamf_application_get_wmclass (app);
 
1184
 
 
1185
      if (app_class != NULL && g_strcmp0 (win_class, app_class) != 0)
 
1186
        {
 
1187
          g_free (app_class);
 
1188
          continue;
 
1189
        }
 
1190
 
1065
1191
      desktop_file = bamf_application_get_desktop_file (app);
1066
 
      
 
1192
 
1067
1193
      if (possible_apps)
1068
1194
        {
1069
1195
          /* primary matching */
1084
1210
          if (bamf_application_contains_similar_to_window (app, bamf_window))
1085
1211
            best = app;
1086
1212
        }
1087
 
        
 
1213
 
 
1214
      g_free (app_class);
1088
1215
      g_free (desktop_file);
1089
1216
    }
1090
1217
 
1095
1222
      else
1096
1223
        best = bamf_application_new ();
1097
1224
 
 
1225
      bamf_application_set_wmclass (best, win_class);
 
1226
 
1098
1227
      bamf_matcher_register_view (self, BAMF_VIEW (best));
1099
1228
      g_object_unref (best);
1100
1229
    }
1101
1230
 
1102
 
 for (l = possible_apps; l; l = l->next)
1103
 
  {
1104
 
    char *str = l->data;
1105
 
    g_free (str);
1106
 
  }
 
1231
  g_free (win_class);
1107
1232
 
 
1233
  for (l = possible_apps; l; l = l->next)
 
1234
    {
 
1235
      char *str = l->data;
 
1236
      g_free (str);
 
1237
    }
1108
1238
 
1109
1239
  g_list_free (possible_apps);
1110
1240
 
1340
1470
  load_desktop_file_to_table (self,
1341
1471
                              desktop_file,
1342
1472
                              self->priv->desktop_file_table,
1343
 
                              self->priv->desktop_id_table);
 
1473
                              self->priv->desktop_id_table,
 
1474
                              self->priv->desktop_class_table);
1344
1475
}
1345
1476
 
1346
1477
void
1731
1862
 
1732
1863
  g_array_free (prefixstrings, TRUE);
1733
1864
 
1734
 
  create_desktop_file_table (self, &(priv->desktop_file_table), &(priv->desktop_id_table));
 
1865
  create_desktop_file_table (self, &(priv->desktop_file_table),
 
1866
                             &(priv->desktop_id_table),
 
1867
                             &(priv->desktop_class_table));
1735
1868
 
1736
1869
  screen = bamf_legacy_screen_get_default ();
1737
1870
  g_signal_connect (G_OBJECT (screen), "window-opened",
1738
 
                    (GCallback) handle_window_opened, self);
 
1871
                    (GCallback) handle_window_opened, self);
1739
1872
 
1740
1873
  approver = bamf_indicator_source_get_default ();
1741
1874
  g_signal_connect (G_OBJECT (approver), "indicator-opened",