1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright (C) 2014 Руслан Ижбулатов
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Authors: Alexander Larsson <alexl@redhat.com>
20 * Руслан Ижбулатов <lrn1986@gmail.com>
27 #include "gcontenttype.h"
28 #include "gwin32appinfo.h"
32 #include <glib/gstdio.h>
34 #include <gio/gwin32registrykey.h>
38 /* We need to watch 8 places:
39 * 0) HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations
40 * (anything below that key)
41 * On change: re-enumerate subkeys, read their values.
42 * 1) HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts
43 * (anything below that key)
44 * On change: re-enumerate subkeys
45 * 2) HKEY_CURRENT_USER\\Software\\Clients (anything below that key)
46 * On change: re-read the whole hierarchy of handlers
47 * 3) HKEY_LOCAL_MACHINE\\Software\\Clients (anything below that key)
48 * On change: re-read the whole hierarchy of handlers
49 * 4) HKEY_LOCAL_MACHINE\\Software\\RegisteredApplications (values of that key)
50 * On change: re-read the value list of registered applications
51 * 5) HKEY_CURRENT_USER\\Software\\RegisteredApplications (values of that key)
52 * On change: re-read the value list of registered applications
53 * 6) HKEY_CLASSES_ROOT\\Applications (anything below that key)
54 * On change: re-read the whole hierarchy of apps
55 * 7) HKEY_CLASSES_ROOT (only its subkeys)
56 * On change: re-enumerate subkeys, try to filter out wrong names.
60 typedef struct _GWin32AppInfoURLSchema GWin32AppInfoURLSchema
;
61 typedef struct _GWin32AppInfoFileExtension GWin32AppInfoFileExtension
;
62 typedef struct _GWin32AppInfoHandler GWin32AppInfoHandler
;
63 typedef struct _GWin32AppInfoApplication GWin32AppInfoApplication
;
65 typedef struct _GWin32AppInfoURLSchemaClass GWin32AppInfoURLSchemaClass
;
66 typedef struct _GWin32AppInfoFileExtensionClass GWin32AppInfoFileExtensionClass
;
67 typedef struct _GWin32AppInfoHandlerClass GWin32AppInfoHandlerClass
;
68 typedef struct _GWin32AppInfoApplicationClass GWin32AppInfoApplicationClass
;
70 struct _GWin32AppInfoURLSchemaClass
72 GObjectClass parent_class
;
75 struct _GWin32AppInfoFileExtensionClass
77 GObjectClass parent_class
;
80 struct _GWin32AppInfoHandlerClass
82 GObjectClass parent_class
;
85 struct _GWin32AppInfoApplicationClass
87 GObjectClass parent_class
;
90 struct _GWin32AppInfoURLSchema
{
91 GObject parent_instance
;
93 /* url schema (stuff before ':') */
96 /* url schema (stuff before ':'), in UTF-8 */
99 /* url schema (stuff before ':'), in UTF-8, folded */
100 gchar
*schema_folded
;
102 /* Handler currently selected for this schema */
103 GWin32AppInfoHandler
*chosen_handler
;
105 /* Maps folded handler IDs -> to other handlers for this schema */
106 GHashTable
*handlers
;
109 struct _GWin32AppInfoHandler
{
110 GObject parent_instance
;
112 /* Class name in HKCR */
113 gunichar2
*handler_id
;
115 /* Handler registry key (HKCR\\handler_id). Can be used to watch this handler. */
116 GWin32RegistryKey
*key
;
118 /* Class name in HKCR, UTF-8, folded */
119 gchar
*handler_id_folded
;
121 /* shell/open/command default value for the class named by class_id */
122 gunichar2
*handler_command
;
124 /* If handler_id class has no command, it might point to another class */
127 /* Proxy registry key (HKCR\\proxy_id). Can be used to watch handler's proxy. */
128 GWin32RegistryKey
*proxy_key
;
130 /* shell/open/command default value for the class named by proxy_id */
131 gunichar2
*proxy_command
;
133 /* Executable of the program (for matching, in folded form; UTF-8) */
134 gchar
*executable_folded
;
136 /* Executable of the program (UTF-8) */
139 /* Pointer to a location within @executable */
140 gchar
*executable_basename
;
142 /* Icon of the application for this handler */
145 /* The application that is linked to this handler. */
146 GWin32AppInfoApplication
*app
;
149 struct _GWin32AppInfoFileExtension
{
150 GObject parent_instance
;
152 /* File extension (with leading '.') */
153 gunichar2
*extension
;
155 /* File extension (with leading '.'), in UTF-8 */
158 /* handler currently selected for this extension */
159 GWin32AppInfoHandler
*chosen_handler
;
161 /* Maps folded handler IDs -> to other handlers for this extension */
162 GHashTable
*handlers
;
164 /* Maps folded app exename -> to apps that support this extension.
165 * ONLY for apps that are not reachable via handlers (i.e. apps from
166 * the HKCR/Applications, which have no handlers). */
167 GHashTable
*other_apps
;
170 struct _GWin32AppInfoApplication
{
171 GObject parent_instance
;
173 /* Canonical name (used for key names). Can be NULL. */
174 gunichar2
*canonical_name
;
176 /* Canonical name (used for key names), in UTF-8. Can be NULL. */
177 gchar
*canonical_name_u8
;
179 /* Canonical name (used for key names), in UTF-8, folded. Can be NULL. */
180 gchar
*canonical_name_folded
;
182 /* Human-readable name in English. Can be NULL */
183 gunichar2
*pretty_name
;
185 /* Human-readable name in English, UTF-8. Can be NULL */
186 gchar
*pretty_name_u8
;
188 /* Human-readable name in user's language. Can be NULL */
189 gunichar2
*localized_pretty_name
;
191 /* Human-readable name in user's language, UTF-8. Can be NULL */
192 gchar
*localized_pretty_name_u8
;
194 /* Description, could be in user's language. Can be NULL */
195 gunichar2
*description
;
197 /* Description, could be in user's language, UTF-8. Can be NULL */
198 gchar
*description_u8
;
200 /* shell/open/command for the application. Can be NULL (see executable). */
203 /* shell/open/command for the application. Can be NULL (see executable). */
206 /* Executable of the program (for matching, in folded form;
207 * UTF-8). Never NULL. */
208 gchar
*executable_folded
;
210 /* Executable of the program (UTF-8). Never NULL. */
213 /* Pointer to a location within @executable */
214 gchar
*executable_basename
;
216 /* Explicitly supported URLs, hashmap from map-owned gchar ptr (schema,
217 * UTF-8, folded) -> a GWin32AppInfoHandler
218 * Schema can be used as a key in the urls hashmap.
220 GHashTable
*supported_urls
;
222 /* Explicitly supported extensions, hashmap from map-owned gchar ptr
223 * (.extension, UTF-8, folded) -> a GWin32AppInfoHandler
224 * Extension can be used as a key in the extensions hashmap.
226 GHashTable
*supported_exts
;
228 /* Icon of the application (remember, handler can have its own icon too) */
231 /* Set to TRUE to prevent this app from appearing in lists of apps for
232 * opening files. This will not prevent it from appearing in lists of apps
233 * just for running, or lists of apps for opening exts/urls for which this
234 * app reports explicit support.
236 gboolean no_open_with
;
238 /* Set to TRUE for applications from HKEY_CURRENT_USER.
239 * Give them priority over applications from HKEY_LOCAL_MACHINE, when all
240 * other things are equal.
242 gboolean user_specific
;
244 /* Set to TRUE for applications that are machine-wide defaults (i.e. default
246 gboolean default_app
;
249 #define G_TYPE_WIN32_APPINFO_URL_SCHEMA (g_win32_appinfo_url_schema_get_type ())
250 #define G_WIN32_APPINFO_URL_SCHEMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_URL_SCHEMA, GWin32AppInfoURLSchema))
252 #define G_TYPE_WIN32_APPINFO_FILE_EXTENSION (g_win32_appinfo_file_extension_get_type ())
253 #define G_WIN32_APPINFO_FILE_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_FILE_EXTENSION, GWin32AppInfoFileExtension))
255 #define G_TYPE_WIN32_APPINFO_HANDLER (g_win32_appinfo_handler_get_type ())
256 #define G_WIN32_APPINFO_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_HANDLER, GWin32AppInfoHandler))
258 #define G_TYPE_WIN32_APPINFO_APPLICATION (g_win32_appinfo_application_get_type ())
259 #define G_WIN32_APPINFO_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_APPLICATION, GWin32AppInfoApplication))
261 GType
g_win32_appinfo_url_schema_get_type (void) G_GNUC_CONST
;
262 GType
g_win32_appinfo_file_extension_get_type (void) G_GNUC_CONST
;
263 GType
g_win32_appinfo_handler_get_type (void) G_GNUC_CONST
;
264 GType
g_win32_appinfo_application_get_type (void) G_GNUC_CONST
;
266 G_DEFINE_TYPE (GWin32AppInfoURLSchema
, g_win32_appinfo_url_schema
, G_TYPE_OBJECT
)
267 G_DEFINE_TYPE (GWin32AppInfoFileExtension
, g_win32_appinfo_file_extension
, G_TYPE_OBJECT
)
268 G_DEFINE_TYPE (GWin32AppInfoHandler
, g_win32_appinfo_handler
, G_TYPE_OBJECT
)
269 G_DEFINE_TYPE (GWin32AppInfoApplication
, g_win32_appinfo_application
, G_TYPE_OBJECT
)
272 g_win32_appinfo_url_schema_dispose (GObject
*object
)
274 GWin32AppInfoURLSchema
*url
= G_WIN32_APPINFO_URL_SCHEMA (object
);
276 g_clear_pointer (&url
->schema
, g_free
);
277 g_clear_pointer (&url
->schema_u8
, g_free
);
278 g_clear_pointer (&url
->schema_folded
, g_free
);
279 g_clear_object (&url
->chosen_handler
);
280 g_clear_pointer (&url
->handlers
, g_hash_table_destroy
);
281 G_OBJECT_CLASS (g_win32_appinfo_url_schema_parent_class
)->dispose (object
);
286 g_win32_appinfo_handler_dispose (GObject
*object
)
288 GWin32AppInfoHandler
*handler
= G_WIN32_APPINFO_HANDLER (object
);
290 g_clear_pointer (&handler
->handler_id
, g_free
);
291 g_clear_pointer (&handler
->handler_id_folded
, g_free
);
292 g_clear_pointer (&handler
->handler_command
, g_free
);
293 g_clear_pointer (&handler
->proxy_id
, g_free
);
294 g_clear_pointer (&handler
->proxy_command
, g_free
);
295 g_clear_pointer (&handler
->executable_folded
, g_free
);
296 g_clear_pointer (&handler
->executable
, g_free
);
297 g_clear_object (&handler
->key
);
298 g_clear_object (&handler
->proxy_key
);
299 g_clear_object (&handler
->icon
);
300 g_clear_object (&handler
->app
);
301 G_OBJECT_CLASS (g_win32_appinfo_handler_parent_class
)->dispose (object
);
305 g_win32_appinfo_file_extension_dispose (GObject
*object
)
307 GWin32AppInfoFileExtension
*ext
= G_WIN32_APPINFO_FILE_EXTENSION (object
);
309 g_clear_pointer (&ext
->extension
, g_free
);
310 g_clear_pointer (&ext
->extension_u8
, g_free
);
311 g_clear_object (&ext
->chosen_handler
);
312 g_clear_pointer (&ext
->handlers
, g_hash_table_destroy
);
313 g_clear_pointer (&ext
->other_apps
, g_hash_table_destroy
);
314 G_OBJECT_CLASS (g_win32_appinfo_file_extension_parent_class
)->dispose (object
);
318 g_win32_appinfo_application_dispose (GObject
*object
)
320 GWin32AppInfoApplication
*app
= G_WIN32_APPINFO_APPLICATION (object
);
322 g_clear_pointer (&app
->canonical_name_u8
, g_free
);
323 g_clear_pointer (&app
->canonical_name_folded
, g_free
);
324 g_clear_pointer (&app
->canonical_name
, g_free
);
325 g_clear_pointer (&app
->pretty_name
, g_free
);
326 g_clear_pointer (&app
->localized_pretty_name
, g_free
);
327 g_clear_pointer (&app
->description
, g_free
);
328 g_clear_pointer (&app
->command
, g_free
);
329 g_clear_pointer (&app
->pretty_name_u8
, g_free
);
330 g_clear_pointer (&app
->localized_pretty_name_u8
, g_free
);
331 g_clear_pointer (&app
->description_u8
, g_free
);
332 g_clear_pointer (&app
->command_u8
, g_free
);
333 g_clear_pointer (&app
->executable_folded
, g_free
);
334 g_clear_pointer (&app
->executable
, g_free
);
335 g_clear_pointer (&app
->supported_urls
, g_hash_table_destroy
);
336 g_clear_pointer (&app
->supported_exts
, g_hash_table_destroy
);
337 g_clear_object (&app
->icon
);
338 G_OBJECT_CLASS (g_win32_appinfo_application_parent_class
)->dispose (object
);
342 g_win32_appinfo_url_schema_class_init (GWin32AppInfoURLSchemaClass
*klass
)
344 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
346 gobject_class
->dispose
= g_win32_appinfo_url_schema_dispose
;
350 g_win32_appinfo_file_extension_class_init (GWin32AppInfoFileExtensionClass
*klass
)
352 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
354 gobject_class
->dispose
= g_win32_appinfo_file_extension_dispose
;
358 g_win32_appinfo_handler_class_init (GWin32AppInfoHandlerClass
*klass
)
360 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
362 gobject_class
->dispose
= g_win32_appinfo_handler_dispose
;
366 g_win32_appinfo_application_class_init (GWin32AppInfoApplicationClass
*klass
)
368 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
370 gobject_class
->dispose
= g_win32_appinfo_application_dispose
;
374 g_win32_appinfo_url_schema_init (GWin32AppInfoURLSchema
*self
)
376 self
->handlers
= g_hash_table_new_full (g_str_hash
,
383 g_win32_appinfo_file_extension_init (GWin32AppInfoFileExtension
*self
)
385 self
->handlers
= g_hash_table_new_full (g_str_hash
,
389 self
->other_apps
= g_hash_table_new_full (g_str_hash
,
396 g_win32_appinfo_handler_init (GWin32AppInfoHandler
*self
)
401 g_win32_appinfo_application_init (GWin32AppInfoApplication
*self
)
403 self
->supported_urls
= g_hash_table_new_full (g_str_hash
,
407 self
->supported_exts
= g_hash_table_new_full (g_str_hash
,
413 G_LOCK_DEFINE_STATIC (gio_win32_appinfo
);
415 /* Map of owned ".ext" (with '.', UTF-8, folded)
416 * to GWin32AppInfoFileExtension ptr
418 static GHashTable
*extensions
= NULL
;
420 /* Map of owned "schema" (without ':', UTF-8, folded)
421 * to GWin32AppInfoURLSchema ptr
423 static GHashTable
*urls
= NULL
;
425 /* Map of owned "appID" (UTF-8, folded) to
426 * GWin32AppInfoApplication ptr
428 static GHashTable
*apps_by_id
= NULL
;
430 /* Map of owned "app.exe" (UTF-8, folded) to
431 * GWin32AppInfoApplication ptr.
432 * This map and its values are separate from apps_by_id. The fact that an app
433 * with known ID has the same executable [base]name as an app in this map does
434 * not mean that they are the same application.
436 static GHashTable
*apps_by_exe
= NULL
;
438 /* Map of owned "handler id" (UTF-8, folded)
439 * to GWin32AppInfoHandler ptr
441 static GHashTable
*handlers
= NULL
;
443 /* Watch this whole subtree */
444 static GWin32RegistryKey
*url_associations_key
;
446 /* Watch this whole subtree */
447 static GWin32RegistryKey
*file_exts_key
;
449 /* Watch this whole subtree */
450 static GWin32RegistryKey
*user_clients_key
;
452 /* Watch this whole subtree */
453 static GWin32RegistryKey
*system_clients_key
;
456 static GWin32RegistryKey
*user_registered_apps_key
;
459 static GWin32RegistryKey
*system_registered_apps_key
;
461 /* Watch this whole subtree */
462 static GWin32RegistryKey
*applications_key
;
465 static GWin32RegistryKey
*classes_root_key
;
468 g_wcsdup (const gunichar2
*str
, gssize str_size
)
472 str_size
= wcslen (str
) + 1;
473 str_size
*= sizeof (gunichar2
);
475 return g_memdup (str
, str_size
);
478 #define URL_ASSOCIATIONS L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
479 #define USER_CHOICE L"\\UserChoice"
480 #define OPEN_WITH_PROGIDS L"\\OpenWithProgids"
481 #define FILE_EXTS L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"
482 #define HKCR L"HKEY_CLASSES_ROOT\\"
483 #define HKCU L"HKEY_CURRENT_USER\\"
484 #define HKLM L"HKEY_LOCAL_MACHINE\\"
485 #define SHELL_OPEN_COMMAND L"\\shell\\open\\command"
486 #define REG_PATH_MAX 256
487 #define REG_PATH_MAX_SIZE (REG_PATH_MAX * sizeof (gunichar2))
490 read_resource_string (gunichar2
*res
)
493 gunichar2
*id_str_end
;
494 gunichar2
*filename_str
;
496 HMODULE resource_module
;
501 if (res
== NULL
|| res
[0] != L
'@')
504 id_str
= wcsrchr (res
, L
'-');
506 if (id_str
== NULL
|| id_str
[-1] != L
',')
511 id
= wcstoul (id_str
, &id_str_end
, 10);
513 if (id_str_end
== id_str
|| id_str_end
[0] != L
'\0' || id
== ULONG_MAX
)
516 filename_str
= &res
[1];
519 resource_module
= LoadLibraryExW (filename_str
,
521 LOAD_LIBRARY_AS_DATAFILE
|
522 LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
526 if (resource_module
== NULL
)
530 string_length
= buffer_length
- 1;
534 buffer
= g_malloc (buffer_length
* sizeof (gunichar2
));
535 string_length
= LoadStringW (resource_module
, id
, buffer
, buffer_length
);
537 if (string_length
!= 0 && string_length
== buffer_length
- 1)
544 if (string_length
== 0)
545 g_clear_pointer (&buffer
, g_free
);
551 FreeLibrary (resource_module
);
555 gunichar2
*result
= g_wcsdup (buffer
, -1);
564 read_handler_icon (GWin32RegistryKey
*proxy_key
,
565 GWin32RegistryKey
*program_key
,
569 GWin32RegistryKey
*key
;
573 for (counter
= 0; counter
< 2; counter
++)
575 GWin32RegistryKey
*icon_key
;
585 icon_key
= g_win32_registry_key_get_child_w (key
, L
"DefaultIcon", NULL
);
587 if (icon_key
!= NULL
)
589 GWin32RegistryValueType default_type
;
590 gchar
*default_value
;
592 if (g_win32_registry_key_get_value (icon_key
,
596 (gpointer
*) &default_value
,
600 if (default_type
== G_WIN32_REGISTRY_VALUE_STR
||
601 default_value
[0] != '\0')
602 *icon_out
= g_themed_icon_new (default_value
);
604 g_clear_pointer (&default_value
, g_free
);
607 g_object_unref (icon_key
);
615 static gboolean
build_registry_path (gunichar2
*output
, gsize output_size
, ...) G_GNUC_NULL_TERMINATED
;
616 static gboolean
build_registry_pathv (gunichar2
*output
, gsize output_size
, va_list components
);
618 static GWin32RegistryKey
*_g_win32_registry_key_build_and_new_w (GError
**error
, ...) G_GNUC_NULL_TERMINATED
;
620 /* output_size is in *bytes*, not gunichar2s! */
622 build_registry_path (gunichar2
*output
, gsize output_size
, ...)
627 va_start (ap
, output_size
);
629 result
= build_registry_pathv (output
, output_size
, ap
);
636 /* output_size is in *bytes*, not gunichar2s! */
638 build_registry_pathv (gunichar2
*output
, gsize output_size
, va_list components
)
642 gunichar2
*component
;
648 G_VA_COPY (lentest
, components
);
650 for (length
= 0, component
= va_arg (lentest
, gunichar2
*);
652 component
= va_arg (lentest
, gunichar2
*))
654 length
+= wcslen (component
);
659 if ((length
>= REG_PATH_MAX_SIZE
) ||
660 (length
* sizeof (gunichar2
) >= output_size
))
665 for (p
= output
, component
= va_arg (components
, gunichar2
*);
667 component
= va_arg (components
, gunichar2
*))
669 length
= wcslen (component
);
670 wcscat (p
, component
);
678 static GWin32RegistryKey
*
679 _g_win32_registry_key_build_and_new_w (GError
**error
, ...)
682 gunichar2 key_path
[REG_PATH_MAX_SIZE
+ 1];
683 GWin32RegistryKey
*key
;
685 va_start (ap
, error
);
689 if (build_registry_pathv (key_path
, sizeof (key_path
), ap
))
690 key
= g_win32_registry_key_new_w (key_path
, error
);
699 utf8_and_fold (const gunichar2
*str
,
701 gchar
**str_u8_folded
)
705 u8
= g_utf16_to_utf8 (str
, -1, NULL
, NULL
, NULL
);
710 folded
= g_utf8_casefold (u8
, -1);
724 *str_u8_folded
= folded
;
733 follow_class_chain_to_handler (const gunichar2
*program_id
,
734 gsize program_id_size
,
735 gunichar2
**program_command
,
736 GWin32RegistryKey
**program_key
,
737 gunichar2
**proxy_id
,
738 gunichar2
**proxy_command
,
739 GWin32RegistryKey
**proxy_key
,
740 gchar
**program_id_u8
,
741 gchar
**program_id_folded
)
743 GWin32RegistryKey
*key
;
744 GWin32RegistryValueType val_type
;
748 g_assert (program_id
&& program_command
&& proxy_id
&& proxy_command
);
750 *program_command
= NULL
;
752 *proxy_command
= NULL
;
761 key
= _g_win32_registry_key_build_and_new_w (NULL
, HKCR
, program_id
,
762 SHELL_OPEN_COMMAND
, NULL
);
766 got_value
= g_win32_registry_key_get_value_w (key
,
770 (void **) program_command
,
773 if (got_value
&& val_type
== G_WIN32_REGISTRY_VALUE_STR
)
775 if ((program_id_u8
!= NULL
|| program_id_folded
!= NULL
) &&
776 !utf8_and_fold (program_id
, program_id_u8
, program_id_folded
))
778 g_object_unref (key
);
779 g_free (program_command
);
783 if (program_key
== NULL
)
784 g_object_unref (key
);
791 g_clear_pointer (program_command
, g_free
);
793 g_object_unref (key
);
796 key
= _g_win32_registry_key_build_and_new_w (NULL
, HKCR
, program_id
, NULL
);
801 got_value
= g_win32_registry_key_get_value_w (key
,
809 (val_type
!= G_WIN32_REGISTRY_VALUE_STR
))
811 g_object_unref (key
);
812 g_clear_pointer (proxy_id
, g_free
);
819 g_object_unref (key
);
821 key
= _g_win32_registry_key_build_and_new_w (NULL
, HKCR
, *proxy_id
,
822 SHELL_OPEN_COMMAND
, NULL
);
826 g_clear_pointer (proxy_id
, g_free
);
828 g_clear_object (proxy_key
);
832 got_value
= g_win32_registry_key_get_value_w (key
,
836 (void **) proxy_command
,
839 g_object_unref (key
);
842 val_type
!= G_WIN32_REGISTRY_VALUE_STR
||
843 ((program_id_u8
!= NULL
|| program_id_folded
!= NULL
) &&
844 !utf8_and_fold (program_id
, program_id_u8
, program_id_folded
)))
846 g_clear_pointer (proxy_id
, g_free
);
847 g_clear_pointer (proxy_command
, g_free
);
849 g_clear_object (proxy_key
);
858 extract_executable (gunichar2
*commandline
,
860 gchar
**ex_basename_out
,
861 gchar
**ex_folded_out
,
862 gchar
**ex_folded_basename_out
)
876 len
= wcslen (commandline
);
879 while (p
< &commandline
[len
])
889 execlen
= p
- commandline
;
890 p
= &commandline
[len
];
903 exepart
= g_wcsdup (commandline
, (execlen
+ 1) * sizeof (gunichar2
));
904 exepart
[execlen
] = L
'\0';
908 while (execlen
> 0 && exepart
[0] == L
'"' && exepart
[execlen
- 1] == L
'"')
911 exepart
[execlen
- 1] = L
'\0';
915 if (!utf8_and_fold (p
, &ex
, &ex_folded
))
916 /* Currently no code to handle this case. It shouldn't happen though... */
917 g_assert_not_reached ();
927 *ex_basename_out
= &ex
[strlen (ex
) - 1];
929 while (*ex_basename_out
> ex
)
931 if ((*ex_basename_out
)[0] == '/' ||
932 (*ex_basename_out
)[0] == '\\')
934 *ex_basename_out
+= 1;
938 *ex_basename_out
-= 1;
949 *ex_folded_out
= ex_folded
;
951 if (ex_folded_basename_out
)
953 *ex_folded_basename_out
= &ex_folded
[strlen (ex_folded
) - 1];
955 while (*ex_folded_basename_out
> ex_folded
)
957 if ((*ex_folded_basename_out
)[0] == '/' ||
958 (*ex_folded_basename_out
)[0] == '\\')
960 *ex_folded_basename_out
+= 1;
964 *ex_folded_basename_out
-= 1;
975 get_url_association (const gunichar2
*schema
)
977 GWin32AppInfoURLSchema
*schema_rec
;
978 GWin32AppInfoHandler
*handler_rec
;
979 GWin32AppInfoHandler
*handler_rec_in_url
;
981 gchar
*schema_folded
;
982 GWin32RegistryKey
*user_choice
;
983 GWin32RegistryValueType val_type
;
984 gunichar2
*program_id
;
985 gsize program_id_size
;
986 gunichar2
*program_command
;
988 gunichar2
*proxy_command
;
989 gchar
*program_id_u8
;
990 gchar
*program_id_folded
;
991 GWin32RegistryKey
*program_key
;
992 GWin32RegistryKey
*proxy_key
;
994 user_choice
= _g_win32_registry_key_build_and_new_w (NULL
, URL_ASSOCIATIONS
,
998 if (user_choice
== NULL
)
1001 if (!utf8_and_fold (schema
, &schema_u8
, &schema_folded
))
1003 g_object_unref (user_choice
);
1007 schema_rec
= g_hash_table_lookup (urls
, schema_folded
);
1009 if (!g_win32_registry_key_get_value_w (user_choice
,
1013 (void **) &program_id
,
1018 g_free (schema_folded
);
1019 g_object_unref (user_choice
);
1023 if (val_type
!= G_WIN32_REGISTRY_VALUE_STR
)
1026 g_free (schema_folded
);
1027 g_free (program_id
);
1028 g_object_unref (user_choice
);
1032 program_key
= proxy_key
= NULL
;
1033 program_command
= proxy_id
= proxy_command
= NULL
;
1035 if (!follow_class_chain_to_handler (program_id
,
1043 &program_id_folded
))
1046 g_free (schema_folded
);
1047 g_free (program_id
);
1048 g_object_unref (user_choice
);
1052 handler_rec
= g_hash_table_lookup (handlers
, program_id_folded
);
1054 if (handler_rec
== NULL
)
1056 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
1058 handler_rec
->proxy_key
= proxy_key
;
1059 handler_rec
->key
= program_key
;
1060 handler_rec
->handler_id
= g_wcsdup (program_id
, program_id_size
);
1061 handler_rec
->handler_id_folded
=
1062 g_strdup (program_id_folded
);
1063 handler_rec
->handler_command
=
1064 program_command
? g_wcsdup (program_command
, -1) : NULL
;
1065 handler_rec
->proxy_id
= proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
1066 handler_rec
->proxy_command
=
1067 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
1068 extract_executable (proxy_command
? proxy_command
: program_command
,
1069 &handler_rec
->executable
,
1070 &handler_rec
->executable_basename
,
1071 &handler_rec
->executable_folded
,
1073 read_handler_icon (proxy_key
, program_key
, &handler_rec
->icon
);
1074 g_hash_table_insert (handlers
,
1075 g_strdup (program_id_folded
),
1080 g_clear_object (&program_key
);
1081 g_clear_object (&proxy_key
);
1084 if (schema_rec
== NULL
)
1086 schema_rec
= g_object_new (G_TYPE_WIN32_APPINFO_URL_SCHEMA
, NULL
);
1087 schema_rec
->schema
= g_wcsdup (schema
, -1);
1088 schema_rec
->schema_u8
= g_strdup (schema_u8
);
1089 schema_rec
->schema_folded
= g_strdup (schema_folded
);
1090 schema_rec
->chosen_handler
= g_object_ref (handler_rec
);
1091 g_hash_table_insert (urls
, g_strdup (schema_folded
), schema_rec
);
1094 if (schema_rec
->chosen_handler
== NULL
)
1095 schema_rec
->chosen_handler
= g_object_ref (handler_rec
);
1097 handler_rec_in_url
= g_hash_table_lookup (schema_rec
->handlers
,
1100 if (handler_rec_in_url
== NULL
&& schema_rec
->chosen_handler
!= handler_rec
)
1101 g_hash_table_insert (schema_rec
->handlers
,
1102 g_strdup (program_id_folded
),
1103 g_object_ref (handler_rec
));
1106 g_free (schema_folded
);
1107 g_free (program_id
);
1108 g_free (program_id_u8
);
1109 g_free (program_id_folded
);
1110 g_free (program_command
);
1112 g_free (proxy_command
);
1113 g_object_unref (user_choice
);
1117 get_file_ext (const gunichar2
*ext
)
1119 GWin32AppInfoFileExtension
*file_extn
;
1120 gboolean file_ext_known
;
1121 GWin32AppInfoHandler
*handler_rec
;
1122 GWin32AppInfoHandler
*handler_rec_in_ext
;
1125 GWin32RegistryKey
*user_choice
;
1126 GWin32RegistryKey
*open_with_progids
;
1127 GWin32RegistryValueType val_type
;
1128 gsize program_id_size
;
1129 gboolean found_handler
;
1130 gunichar2
*program_id
;
1131 gunichar2
*proxy_id
;
1132 gchar
*program_id_u8
;
1133 gchar
*program_id_folded
;
1134 GWin32RegistryKey
*program_key
;
1135 GWin32RegistryKey
*proxy_key
;
1136 gunichar2
*program_command
;
1137 gunichar2
*proxy_command
;
1139 open_with_progids
= _g_win32_registry_key_build_and_new_w (NULL
, FILE_EXTS
,
1144 user_choice
= _g_win32_registry_key_build_and_new_w (NULL
, FILE_EXTS
, ext
,
1147 if (user_choice
== NULL
&& open_with_progids
== NULL
)
1150 if (!utf8_and_fold (ext
, &ext_u8
, &ext_folded
))
1152 g_clear_object (&user_choice
);
1153 g_clear_object (&open_with_progids
);
1158 file_ext_known
= g_hash_table_lookup_extended (extensions
,
1161 (void **) &file_extn
);
1163 if (!file_ext_known
)
1164 file_extn
= g_object_new (G_TYPE_WIN32_APPINFO_FILE_EXTENSION
, NULL
);
1166 found_handler
= FALSE
;
1168 if (user_choice
!= NULL
)
1170 if (g_win32_registry_key_get_value_w (user_choice
,
1174 (void **) &program_id
,
1178 program_key
= proxy_key
= NULL
;
1180 if (val_type
== G_WIN32_REGISTRY_VALUE_STR
&&
1181 follow_class_chain_to_handler (program_id
,
1189 &program_id_folded
))
1191 handler_rec
= g_hash_table_lookup (handlers
,
1194 if (handler_rec
== NULL
)
1196 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
,
1198 handler_rec
->proxy_key
= proxy_key
;
1199 handler_rec
->key
= program_key
;
1200 handler_rec
->handler_id
=
1201 g_wcsdup (program_id
, program_id_size
);
1202 handler_rec
->handler_id_folded
=
1203 g_strdup (program_id_folded
);
1204 handler_rec
->handler_command
=
1205 program_command
? g_wcsdup (program_command
, -1) : NULL
;
1206 handler_rec
->proxy_id
=
1207 proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
1208 handler_rec
->proxy_command
=
1209 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
1210 extract_executable (proxy_command
? proxy_command
: program_command
,
1211 &handler_rec
->executable
,
1212 &handler_rec
->executable_basename
,
1213 &handler_rec
->executable_folded
,
1215 read_handler_icon (proxy_key
,
1217 &handler_rec
->icon
);
1218 g_hash_table_insert (handlers
,
1219 g_strdup (program_id_folded
),
1224 g_clear_object (&program_key
);
1225 g_clear_object (&proxy_key
);
1228 found_handler
= TRUE
;
1230 handler_rec_in_ext
= g_hash_table_lookup (file_extn
->handlers
,
1233 if (file_extn
->chosen_handler
== NULL
)
1235 g_hash_table_insert (file_extn
->handlers
,
1236 g_strdup (program_id_folded
),
1237 g_object_ref (handler_rec
));
1239 else if (handler_rec_in_ext
== NULL
)
1241 if (file_extn
->chosen_handler
->handler_id_folded
&&
1242 strcmp (file_extn
->chosen_handler
->handler_id_folded
,
1243 program_id_folded
) != 0)
1244 g_hash_table_insert (file_extn
->handlers
,
1245 g_strdup (program_id_folded
),
1246 g_object_ref (handler_rec
));
1249 g_free (program_id_u8
);
1250 g_free (program_id_folded
);
1251 g_free (program_command
);
1253 g_free (proxy_command
);
1256 g_free (program_id
);
1259 g_object_unref (user_choice
);
1262 if (open_with_progids
!= NULL
)
1264 GWin32RegistryValueIter iter
;
1266 if (g_win32_registry_value_iter_init (&iter
, open_with_progids
, NULL
))
1268 gunichar2
*value_name
;
1269 gunichar2
*value_data
;
1270 gsize value_name_len
;
1271 gsize value_data_size
;
1272 GWin32RegistryValueType value_type
;
1274 while (g_win32_registry_value_iter_next (&iter
, TRUE
, NULL
))
1276 gsize value_name_size
;
1277 program_key
= proxy_key
= NULL
;
1279 if ((!g_win32_registry_value_iter_get_value_type (&iter
,
1282 ((val_type
!= G_WIN32_REGISTRY_VALUE_STR
) &&
1283 (val_type
!= G_WIN32_REGISTRY_VALUE_EXPAND_STR
)) ||
1284 (!g_win32_registry_value_iter_get_name_w (&iter
, &value_name
,
1287 (value_name_len
<= 0) ||
1288 (!g_win32_registry_value_iter_get_data_w (&iter
, TRUE
,
1289 (void **) &value_data
,
1292 (value_data_size
< sizeof (gunichar2
)) ||
1293 (value_data
[0] == L
'\0'))
1296 value_name_size
= sizeof (gunichar2
) * (value_name_len
+ 1);
1298 if (!follow_class_chain_to_handler (value_name
,
1306 &program_id_folded
))
1309 handler_rec
= g_hash_table_lookup (handlers
,
1312 if (handler_rec
== NULL
)
1314 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
1316 handler_rec
->proxy_key
= proxy_key
;
1317 handler_rec
->key
= program_key
;
1318 handler_rec
->handler_id
=
1319 g_wcsdup (value_name
, value_name_size
);
1320 handler_rec
->handler_id_folded
=
1321 g_strdup (program_id_folded
);
1322 handler_rec
->handler_command
=
1323 program_command
? g_wcsdup (program_command
, -1) : NULL
;
1324 handler_rec
->proxy_id
=
1325 proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
1326 handler_rec
->proxy_command
=
1327 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
1328 extract_executable (proxy_command
? proxy_command
: program_command
,
1329 &handler_rec
->executable
,
1330 &handler_rec
->executable_basename
,
1331 &handler_rec
->executable_folded
,
1333 read_handler_icon (proxy_key
,
1335 &handler_rec
->icon
);
1336 g_hash_table_insert (handlers
,
1337 g_strdup (program_id_folded
),
1342 g_clear_object (&program_key
);
1343 g_clear_object (&proxy_key
);
1346 found_handler
= TRUE
;
1348 handler_rec_in_ext
= g_hash_table_lookup (file_extn
->handlers
,
1351 if (handler_rec_in_ext
== NULL
)
1353 if (file_extn
->chosen_handler
== NULL
)
1354 g_hash_table_insert (file_extn
->handlers
,
1355 g_strdup (program_id_folded
),
1356 g_object_ref (handler_rec
));
1357 else if (file_extn
->chosen_handler
->handler_id_folded
&&
1358 strcmp (file_extn
->chosen_handler
->handler_id_folded
,
1359 program_id_folded
) != 0)
1360 g_hash_table_insert (file_extn
->handlers
,
1361 g_strdup (program_id_folded
),
1362 g_object_ref (handler_rec
));
1365 g_free (program_id_u8
);
1366 g_free (program_id_folded
);
1367 g_free (program_command
);
1369 g_free (proxy_command
);
1372 g_win32_registry_value_iter_clear (&iter
);
1375 g_object_unref (open_with_progids
);
1380 if (!file_ext_known
)
1381 g_object_unref (file_extn
);
1383 else if (!file_ext_known
)
1385 file_extn
->extension
= g_wcsdup (ext
, -1);
1386 file_extn
->extension_u8
= g_strdup (ext_u8
);
1387 g_hash_table_insert (extensions
, g_strdup (ext_folded
), file_extn
);
1391 g_free (ext_folded
);
1395 collect_capable_apps_from_clients (GPtrArray
*capable_apps
,
1396 GPtrArray
*priority_capable_apps
,
1397 gboolean user_registry
)
1399 GWin32RegistryKey
*clients
;
1400 GWin32RegistrySubkeyIter clients_iter
;
1402 gunichar2
*client_type_name
;
1403 gsize client_type_name_len
;
1408 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Clients",
1412 g_win32_registry_key_new_w (L
"HKEY_LOCAL_MACHINE\\Software\\Clients",
1415 if (clients
== NULL
)
1418 if (!g_win32_registry_subkey_iter_init (&clients_iter
, clients
, NULL
))
1420 g_object_unref (clients
);
1424 while (g_win32_registry_subkey_iter_next (&clients_iter
, TRUE
, NULL
))
1426 GWin32RegistrySubkeyIter subkey_iter
;
1427 GWin32RegistryKey
*system_client_type
;
1428 GWin32RegistryValueType default_type
;
1429 gunichar2
*default_value
;
1430 gunichar2
*client_name
;
1431 gsize client_name_len
;
1433 if (!g_win32_registry_subkey_iter_get_name_w (&clients_iter
,
1435 &client_type_name_len
,
1439 system_client_type
= g_win32_registry_key_get_child_w (clients
,
1443 if (system_client_type
== NULL
)
1446 if (g_win32_registry_key_get_value_w (system_client_type
,
1450 (gpointer
*) &default_value
,
1454 if (default_type
!= G_WIN32_REGISTRY_VALUE_STR
||
1455 default_value
[0] == L
'\0')
1456 g_clear_pointer (&default_value
, g_free
);
1459 if (!g_win32_registry_subkey_iter_init (&subkey_iter
,
1463 g_clear_pointer (&default_value
, g_free
);
1464 g_object_unref (system_client_type
);
1468 while (g_win32_registry_subkey_iter_next (&subkey_iter
, TRUE
, NULL
))
1470 GWin32RegistryKey
*system_client
;
1471 GWin32RegistryKey
*system_client_assoc
;
1475 if (!g_win32_registry_subkey_iter_get_name_w (&subkey_iter
,
1481 system_client
= g_win32_registry_key_get_child_w (system_client_type
,
1485 if (system_client
== NULL
)
1490 system_client_assoc
= g_win32_registry_key_get_child_w (system_client
,
1491 L
"Capabilities\\FileAssociations",
1494 if (system_client_assoc
!= NULL
)
1497 g_object_unref (system_client_assoc
);
1501 system_client_assoc
= g_win32_registry_key_get_child_w (system_client
,
1502 L
"Capabilities\\UrlAssociations",
1505 if (system_client_assoc
!= NULL
)
1508 g_object_unref (system_client_assoc
);
1514 keyname
= g_wcsdup (g_win32_registry_key_get_path_w (system_client
), -1);
1516 if (default_value
&& wcscmp (default_value
, client_name
) == 0)
1517 g_ptr_array_add (priority_capable_apps
, keyname
);
1519 g_ptr_array_add (capable_apps
, keyname
);
1522 g_object_unref (system_client
);
1525 g_win32_registry_subkey_iter_clear (&subkey_iter
);
1526 g_clear_pointer (&default_value
, g_free
);
1527 g_object_unref (system_client_type
);
1530 g_win32_registry_subkey_iter_clear (&clients_iter
);
1531 g_object_unref (clients
);
1535 collect_capable_apps_from_registered_apps (GPtrArray
*capable_apps
,
1536 gboolean user_registry
)
1538 GWin32RegistryValueIter iter
;
1540 gunichar2
*value_data
;
1541 gsize value_data_size
;
1542 GWin32RegistryValueType value_type
;
1543 GWin32RegistryKey
*registered_apps
;
1547 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\RegisteredApplications",
1551 g_win32_registry_key_new_w (L
"HKEY_LOCAL_MACHINE\\Software\\RegisteredApplications",
1554 if (!registered_apps
)
1557 if (!g_win32_registry_value_iter_init (&iter
, registered_apps
, NULL
))
1559 g_object_unref (registered_apps
);
1563 while (g_win32_registry_value_iter_next (&iter
, TRUE
, NULL
))
1565 gunichar2 possible_location
[REG_PATH_MAX_SIZE
+ 1];
1566 GWin32RegistryKey
*location
= NULL
;
1568 if ((!g_win32_registry_value_iter_get_value_type (&iter
,
1571 (value_type
!= G_WIN32_REGISTRY_VALUE_STR
) ||
1572 (!g_win32_registry_value_iter_get_data_w (&iter
, TRUE
,
1573 (void **) &value_data
,
1576 (value_data_size
< sizeof (gunichar2
)) ||
1577 (value_data
[0] == L
'\0'))
1580 if (build_registry_path (possible_location
, sizeof (possible_location
),
1581 HKCU
, value_data
, NULL
))
1582 location
= g_win32_registry_key_new_w (possible_location
, NULL
);
1586 gunichar2
*p
= wcsrchr (possible_location
, L
'\\');
1591 g_ptr_array_add (capable_apps
, g_wcsdup (possible_location
, -1));
1592 g_object_unref (location
);
1596 if (!build_registry_path (possible_location
, sizeof (possible_location
),
1597 user_registry
? HKCU
: HKLM
, value_data
, NULL
))
1600 location
= g_win32_registry_key_new_w (possible_location
, NULL
);
1604 gunichar2
*p
= wcsrchr (possible_location
, L
'\\');
1607 g_ptr_array_add (capable_apps
, g_wcsdup (possible_location
, -1));
1608 g_object_unref (location
);
1612 g_win32_registry_value_iter_clear (&iter
);
1613 g_object_unref (registered_apps
);
1617 read_capable_app (gunichar2
*input_app_key_path
, gboolean user_specific
, gboolean default_app
)
1619 GWin32AppInfoApplication
*app
;
1620 gunichar2
*app_key_path
;
1621 gunichar2
*canonical_name
;
1622 gchar
*canonical_name_u8
;
1623 gchar
*canonical_name_folded
;
1624 GWin32RegistryKey
*appkey
;
1625 gunichar2
*fallback_friendly_name
;
1626 GWin32RegistryValueType vtype
;
1628 gunichar2
*friendly_name
;
1629 gunichar2
*description
;
1630 gunichar2
*narrow_application_name
;
1631 gunichar2
*icon_source
;
1632 GWin32RegistryKey
*capabilities
;
1633 GWin32RegistryKey
*default_icon_key
;
1634 GWin32RegistryKey
*shell_open_command_key
;
1635 gunichar2
*shell_open_command
;
1636 gchar
*app_executable
;
1637 gchar
*app_executable_basename
;
1638 gchar
*app_executable_folded
;
1639 gchar
*app_executable_folded_basename
;
1640 GWin32RegistryKey
*associations
;
1642 app_key_path
= g_wcsdup (input_app_key_path
, -1);
1644 canonical_name
= wcsrchr (app_key_path
, L
'\\');
1646 if (canonical_name
== NULL
)
1648 /* The key must have at least one '\\' */
1649 g_free (app_key_path
);
1653 canonical_name
+= 1;
1655 if (!utf8_and_fold (canonical_name
, &canonical_name_u8
, &canonical_name_folded
))
1657 g_free (app_key_path
);
1661 appkey
= g_win32_registry_key_new_w (app_key_path
, NULL
);
1665 g_free (canonical_name_u8
);
1666 g_free (canonical_name_folded
);
1667 g_free (app_key_path
);
1672 g_win32_registry_key_get_child_w (appkey
, L
"Capabilities", NULL
);
1674 if (capabilities
== NULL
)
1676 /* Must have capabilities */
1677 g_free (canonical_name_u8
);
1678 g_free (canonical_name_folded
);
1679 g_free (app_key_path
);
1683 shell_open_command_key
=
1684 g_win32_registry_key_get_child_w (appkey
,
1685 L
"shell\\open\\command",
1688 if (shell_open_command_key
== NULL
)
1690 g_object_unref (capabilities
);
1691 g_free (canonical_name_u8
);
1692 g_free (canonical_name_folded
);
1693 g_free (app_key_path
);
1694 g_object_unref (appkey
);
1698 shell_open_command
= NULL
;
1700 success
= g_win32_registry_key_get_value_w (shell_open_command_key
,
1704 (gpointer
*) &shell_open_command
,
1708 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1710 /* Must have a command */
1711 g_clear_pointer (&shell_open_command
, g_free
);
1712 g_object_unref (capabilities
);
1713 g_free (canonical_name_u8
);
1714 g_free (canonical_name_folded
);
1715 g_free (app_key_path
);
1716 g_object_unref (appkey
);
1720 extract_executable (shell_open_command
,
1722 &app_executable_basename
,
1723 &app_executable_folded
,
1724 &app_executable_folded_basename
);
1726 app
= g_hash_table_lookup (apps_by_id
, canonical_name_folded
);
1730 app
= g_object_new (G_TYPE_WIN32_APPINFO_APPLICATION
, NULL
);
1732 app
->canonical_name
= g_wcsdup (canonical_name
, -1);
1733 app
->canonical_name_u8
= g_strdup (canonical_name_u8
);
1734 app
->canonical_name_folded
=
1735 g_strdup (canonical_name_folded
);
1737 app
->command
= g_wcsdup (shell_open_command
, -1);
1739 g_utf16_to_utf8 (shell_open_command
, -1, NULL
, NULL
, NULL
);
1740 app
->executable
= g_strdup (app_executable
);
1741 app
->executable_basename
=
1742 &app
->executable
[app_executable_basename
- app_executable
];
1743 app
->executable_folded
=
1744 g_strdup (app_executable_folded
);
1746 app
->no_open_with
= FALSE
;
1748 app
->user_specific
= user_specific
;
1749 app
->default_app
= default_app
;
1751 g_hash_table_insert (apps_by_id
,
1752 g_strdup (canonical_name_folded
),
1756 fallback_friendly_name
= NULL
;
1757 success
= g_win32_registry_key_get_value_w (appkey
,
1761 (void **) &fallback_friendly_name
,
1765 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1766 g_clear_pointer (&fallback_friendly_name
, g_free
);
1768 if (fallback_friendly_name
&& app
->pretty_name
== NULL
)
1770 app
->pretty_name
= g_wcsdup (fallback_friendly_name
, -1);
1771 g_clear_pointer (&app
->pretty_name_u8
, g_free
);
1772 app
->pretty_name_u8
= g_utf16_to_utf8 (fallback_friendly_name
,
1779 friendly_name
= NULL
;
1780 success
= g_win32_registry_key_get_value_w (capabilities
,
1784 (void **) &friendly_name
,
1788 if (success
&& (vtype
!= G_WIN32_REGISTRY_VALUE_STR
|| friendly_name
[0] != L
'@'))
1789 g_clear_pointer (&friendly_name
, g_free
);
1791 friendly_name
= read_resource_string (friendly_name
);
1793 if (friendly_name
&& app
->localized_pretty_name
== NULL
)
1795 app
->localized_pretty_name
= g_wcsdup (friendly_name
, -1);
1796 g_clear_pointer (&app
->localized_pretty_name_u8
, g_free
);
1797 app
->localized_pretty_name_u8
= g_utf16_to_utf8 (friendly_name
,
1805 success
= g_win32_registry_key_get_value_w (capabilities
,
1807 L
"ApplicationDescription",
1809 (void **) &description
,
1813 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1814 g_clear_pointer (&description
, g_free
);
1816 description
= read_resource_string (description
);
1818 if (description
&& app
->description
== NULL
)
1820 app
->description
= g_wcsdup (description
, -1);
1821 g_clear_pointer (&app
->description_u8
, g_free
);
1822 app
->description_u8
= g_utf16_to_utf8 (description
, -1, NULL
, NULL
, NULL
);
1825 default_icon_key
= g_win32_registry_key_get_child_w (appkey
,
1831 if (default_icon_key
!= NULL
)
1833 success
= g_win32_registry_key_get_value_w (default_icon_key
,
1837 (void **) &icon_source
,
1841 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1842 g_clear_pointer (&icon_source
, g_free
);
1844 g_object_unref (default_icon_key
);
1847 if (icon_source
== NULL
)
1849 success
= g_win32_registry_key_get_value_w (capabilities
,
1853 (void **) &icon_source
,
1857 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1858 g_clear_pointer (&icon_source
, g_free
);
1861 if (icon_source
&& app
->icon
== NULL
)
1863 gchar
*name
= g_utf16_to_utf8 (icon_source
, -1, NULL
, NULL
, NULL
);
1864 app
->icon
= g_themed_icon_new (name
);
1868 narrow_application_name
= NULL
;
1869 success
= g_win32_registry_key_get_value_w (capabilities
,
1873 (void **) &narrow_application_name
,
1877 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
1878 g_clear_pointer (&narrow_application_name
, g_free
);
1880 narrow_application_name
= read_resource_string (narrow_application_name
);
1882 /* TODO: do something with the narrow name. Maybe make a kind of sub-app?
1883 * Narrow name is a more precise name of the application in given context.
1884 * I.e. Thunderbird's name is "Thunderbird", whereas its narrow name is
1885 * "Thunderbird (news)" when registering it as a news client.
1886 * Maybe we should consider applications with different narrow names as
1887 * different applications altogether?
1890 associations
= g_win32_registry_key_get_child_w (capabilities
,
1891 L
"FileAssociations",
1894 if (associations
!= NULL
)
1896 GWin32RegistryValueIter iter
;
1898 if (g_win32_registry_value_iter_init (&iter
, associations
, NULL
))
1900 gunichar2
*file_extension
;
1901 gunichar2
*extension_handler
;
1902 gsize file_extension_len
;
1903 gsize extension_handler_size
;
1904 GWin32RegistryValueType value_type
;
1906 while (g_win32_registry_value_iter_next (&iter
, TRUE
, NULL
))
1908 GWin32AppInfoHandler
*handler_rec
;
1909 GWin32AppInfoHandler
*handler_rec_in_ext
;
1910 GWin32AppInfoFileExtension
*ext
;
1911 gunichar2
*program_command
;
1912 gunichar2
*proxy_id
;
1913 gunichar2
*proxy_command
;
1914 GWin32RegistryKey
*program_key
;
1915 GWin32RegistryKey
*proxy_key
;
1916 gchar
*program_id_u8
;
1917 gchar
*program_id_folded
;
1918 gchar
*file_extension_u8
;
1919 gchar
*file_extension_folded
;
1921 if ((!g_win32_registry_value_iter_get_value_type (&iter
,
1924 (value_type
!= G_WIN32_REGISTRY_VALUE_STR
) ||
1925 (!g_win32_registry_value_iter_get_name_w (&iter
,
1927 &file_extension_len
,
1929 (file_extension_len
<= 0) ||
1930 (file_extension
[0] != L
'.') ||
1931 (!g_win32_registry_value_iter_get_data_w (&iter
, TRUE
,
1932 (void **) &extension_handler
,
1933 &extension_handler_size
,
1935 (extension_handler_size
< sizeof (gunichar2
)) ||
1936 (extension_handler
[0] == L
'\0'))
1939 if (!follow_class_chain_to_handler (extension_handler
,
1940 extension_handler_size
,
1947 &program_id_folded
))
1950 handler_rec
= g_hash_table_lookup (handlers
,
1953 if (handler_rec
== NULL
)
1955 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
1957 handler_rec
->proxy_key
= proxy_key
;
1958 handler_rec
->key
= program_key
;
1959 handler_rec
->handler_id
=
1960 g_wcsdup (extension_handler
,extension_handler_size
);
1961 handler_rec
->handler_id_folded
=
1962 g_strdup (program_id_folded
);
1963 handler_rec
->handler_command
=
1964 program_command
? g_wcsdup (program_command
, -1) : NULL
;
1965 handler_rec
->proxy_id
=
1966 proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
1967 handler_rec
->proxy_command
=
1968 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
1969 extract_executable (proxy_command
? proxy_command
: program_command
,
1970 &handler_rec
->executable
,
1971 &handler_rec
->executable_basename
,
1972 &handler_rec
->executable_folded
,
1974 read_handler_icon (proxy_key
,
1976 &handler_rec
->icon
);
1977 g_hash_table_insert (handlers
,
1978 g_strdup (program_id_folded
),
1983 g_clear_object (&program_key
);
1984 g_clear_object (&proxy_key
);
1987 if (utf8_and_fold (file_extension
,
1989 &file_extension_folded
))
1991 ext
= g_hash_table_lookup (extensions
,
1992 file_extension_folded
);
1996 ext
= g_object_new (G_TYPE_WIN32_APPINFO_FILE_EXTENSION
, NULL
);
1998 ext
->extension
= g_wcsdup (file_extension
, -1);
1999 ext
->extension_u8
= g_strdup (file_extension_u8
);
2000 g_hash_table_insert (extensions
, g_strdup (file_extension_folded
), ext
);
2003 handler_rec_in_ext
=
2004 g_hash_table_lookup (ext
->handlers
,
2007 if (handler_rec_in_ext
== NULL
)
2009 if (ext
->chosen_handler
== NULL
)
2010 g_hash_table_insert (ext
->handlers
,
2011 g_strdup (program_id_folded
),
2012 g_object_ref (handler_rec
));
2013 else if (ext
->chosen_handler
->handler_id_folded
&&
2014 strcmp (ext
->chosen_handler
->handler_id_folded
,
2015 program_id_folded
) != 0)
2016 g_hash_table_insert (ext
->handlers
,
2017 g_strdup (program_id_folded
),
2018 g_object_ref (handler_rec
));
2021 handler_rec_in_ext
=
2022 g_hash_table_lookup (app
->supported_exts
,
2023 file_extension_folded
);
2025 if (handler_rec_in_ext
== NULL
)
2026 g_hash_table_insert (app
->supported_exts
,
2027 g_strdup (file_extension_folded
),
2028 g_object_ref (handler_rec
));
2030 g_free (file_extension_u8
);
2031 g_free (file_extension_folded
);
2034 g_free (program_id_u8
);
2035 g_free (program_id_folded
);
2036 g_free (program_command
);
2038 g_free (proxy_command
);
2041 g_win32_registry_value_iter_clear (&iter
);
2044 g_object_unref (associations
);
2047 associations
= g_win32_registry_key_get_child_w (capabilities
, L
"URLAssociations", NULL
);
2049 if (associations
!= NULL
)
2051 GWin32RegistryValueIter iter
;
2053 if (g_win32_registry_value_iter_init (&iter
, associations
, NULL
))
2055 gunichar2
*url_schema
;
2056 gunichar2
*schema_handler
;
2057 gsize url_schema_len
;
2058 gsize schema_handler_size
;
2059 GWin32RegistryValueType value_type
;
2061 while (g_win32_registry_value_iter_next (&iter
, TRUE
, NULL
))
2063 GWin32AppInfoHandler
*handler_rec
;
2064 GWin32AppInfoHandler
*handler_rec_in_url
;
2065 GWin32AppInfoURLSchema
*schema
;
2066 gunichar2
*program_command
;
2067 gunichar2
*proxy_id
;
2068 gunichar2
*proxy_command
;
2069 GWin32RegistryKey
*program_key
;
2070 GWin32RegistryKey
*proxy_key
;
2071 gchar
*program_id_u8
;
2072 gchar
*program_id_folded
;
2074 gchar
*schema_folded
;
2076 if ((!g_win32_registry_value_iter_get_value_type (&iter
,
2079 ((value_type
!= G_WIN32_REGISTRY_VALUE_STR
) &&
2080 (value_type
!= G_WIN32_REGISTRY_VALUE_EXPAND_STR
)) ||
2081 (!g_win32_registry_value_iter_get_name_w (&iter
,
2085 (url_schema_len
<= 0) ||
2086 (url_schema
[0] == L
'\0') ||
2087 (!g_win32_registry_value_iter_get_data_w (&iter
, TRUE
,
2088 (void **) &schema_handler
,
2089 &schema_handler_size
,
2091 (schema_handler_size
< sizeof (gunichar2
)) ||
2092 (schema_handler
[0] == L
'\0'))
2095 if (!follow_class_chain_to_handler (schema_handler
,
2096 schema_handler_size
,
2103 &program_id_folded
))
2107 handler_rec
= g_hash_table_lookup (handlers
, program_id_folded
);
2109 if (handler_rec
== NULL
)
2111 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
2113 handler_rec
->proxy_key
= proxy_key
;
2114 handler_rec
->key
= program_key
;
2115 handler_rec
->handler_id
=
2116 g_wcsdup (schema_handler
, schema_handler_size
);
2117 handler_rec
->handler_id_folded
=
2118 g_strdup (program_id_folded
);
2119 handler_rec
->handler_command
= program_command
?
2120 g_wcsdup (program_command
, -1) : NULL
;
2121 handler_rec
->proxy_id
=
2122 proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
2123 handler_rec
->proxy_command
=
2124 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
2125 extract_executable (proxy_command
? proxy_command
: program_command
,
2126 &handler_rec
->executable
,
2127 &handler_rec
->executable_basename
,
2128 &handler_rec
->executable_folded
,
2130 read_handler_icon (proxy_key
,
2132 &handler_rec
->icon
);
2133 g_hash_table_insert (handlers
,
2134 g_strdup (program_id_folded
),
2139 g_clear_object (&program_key
);
2140 g_clear_object (&proxy_key
);
2143 if (utf8_and_fold (url_schema
,
2147 schema
= g_hash_table_lookup (urls
,
2152 schema
= g_object_new (G_TYPE_WIN32_APPINFO_URL_SCHEMA
, NULL
);
2154 schema
->schema
= g_wcsdup (url_schema
, -1);
2155 schema
->schema_u8
= g_strdup (schema_u8
);
2156 schema
->schema_folded
=
2157 g_strdup (schema_folded
);
2158 g_hash_table_insert (urls
,
2159 g_strdup (schema_folded
),
2163 handler_rec_in_url
=
2164 g_hash_table_lookup (schema
->handlers
,
2167 if (handler_rec_in_url
== NULL
)
2168 g_hash_table_insert (schema
->handlers
,
2169 g_strdup (program_id_folded
),
2170 g_object_ref (handler_rec
));
2172 handler_rec_in_url
=
2173 g_hash_table_lookup (app
->supported_urls
,
2176 if (handler_rec_in_url
== NULL
)
2177 g_hash_table_insert (app
->supported_urls
,
2178 g_strdup (schema_folded
),
2179 g_object_ref (handler_rec
));
2182 g_free (schema_folded
);
2185 g_free (program_id_u8
);
2186 g_free (program_id_folded
);
2187 g_free (program_command
);
2189 g_free (proxy_command
);
2192 g_win32_registry_value_iter_clear (&iter
);
2195 g_object_unref (associations
);
2198 g_clear_pointer (&app_executable
, g_free
);
2199 g_clear_pointer (&app_executable_folded
, g_free
);
2200 g_clear_pointer (&fallback_friendly_name
, g_free
);
2201 g_clear_pointer (&description
, g_free
);
2202 g_clear_pointer (&icon_source
, g_free
);
2203 g_clear_pointer (&narrow_application_name
, g_free
);
2204 g_clear_pointer (&shell_open_command
, g_free
);
2206 g_object_unref (appkey
);
2207 g_object_unref (shell_open_command_key
);
2208 g_object_unref (capabilities
);
2209 g_free (canonical_name_u8
);
2210 g_free (canonical_name_folded
);
2211 g_free (app_key_path
);
2215 read_urls (GWin32RegistryKey
*url_associations
)
2217 GWin32RegistrySubkeyIter url_iter
;
2218 gunichar2
*url_schema
;
2219 gsize url_schema_len
;
2221 if (url_associations
== NULL
)
2224 if (!g_win32_registry_subkey_iter_init (&url_iter
, url_associations
, NULL
))
2227 while (g_win32_registry_subkey_iter_next (&url_iter
, TRUE
, NULL
))
2229 if (!g_win32_registry_subkey_iter_get_name_w (&url_iter
,
2235 get_url_association (url_schema
);
2238 g_win32_registry_subkey_iter_clear (&url_iter
);
2244 GWin32RegistryKey
*applications_key
;
2245 GWin32RegistrySubkeyIter app_iter
;
2246 gunichar2
*app_exe_basename
;
2247 gsize app_exe_basename_len
;
2250 g_win32_registry_key_new_w (L
"HKEY_CLASSES_ROOT\\Applications", NULL
);
2252 if (applications_key
== NULL
)
2255 if (!g_win32_registry_subkey_iter_init (&app_iter
, applications_key
, NULL
))
2257 g_object_unref (applications_key
);
2261 while (g_win32_registry_subkey_iter_next (&app_iter
, TRUE
, NULL
))
2263 GWin32RegistryKey
*incapable_app
;
2264 gunichar2
*friendly_app_name
;
2266 gboolean no_open_with
;
2267 GWin32RegistryValueType vtype
;
2268 GWin32RegistryKey
*default_icon_key
;
2269 gunichar2
*icon_source
;
2272 gchar
*appexe_basename
;
2273 gchar
*appexe_folded
;
2274 gchar
*appexe_folded_basename
;
2275 GWin32AppInfoApplication
*app
;
2276 GWin32RegistryKey
*shell_open_command_key
;
2277 gunichar2
*shell_open_command
;
2278 GWin32RegistryKey
*supported_key
;
2280 if (!g_win32_registry_subkey_iter_get_name_w (&app_iter
,
2282 &app_exe_basename_len
,
2287 g_win32_registry_key_get_child_w (applications_key
,
2291 if (incapable_app
== NULL
)
2294 extract_executable (app_exe_basename
,
2298 &appexe_folded_basename
);
2300 shell_open_command_key
=
2301 g_win32_registry_key_get_child_w (incapable_app
,
2302 L
"shell\\open\\command",
2305 shell_open_command
= NULL
;
2307 if (shell_open_command_key
!= NULL
)
2309 success
= g_win32_registry_key_get_value_w (shell_open_command_key
,
2313 (gpointer
*) &shell_open_command
,
2317 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
2319 g_clear_pointer (&shell_open_command
, g_free
);
2322 g_object_unref (shell_open_command_key
);
2325 friendly_app_name
= NULL
;
2326 success
= g_win32_registry_key_get_value_w (incapable_app
,
2330 (void **) &friendly_app_name
,
2334 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
2335 g_clear_pointer (&friendly_app_name
, g_free
);
2337 friendly_app_name
= read_resource_string (friendly_app_name
);
2339 no_open_with
= FALSE
;
2340 success
= g_win32_registry_key_get_value_w (incapable_app
,
2349 no_open_with
= TRUE
;
2352 g_win32_registry_key_get_child_w (incapable_app
,
2358 if (default_icon_key
!= NULL
)
2361 g_win32_registry_key_get_value_w (default_icon_key
,
2365 (void **) &icon_source
,
2369 if (success
&& vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
2370 g_clear_pointer (&icon_source
, g_free
);
2372 g_object_unref (default_icon_key
);
2377 gchar
*name
= g_utf16_to_utf8 (icon_source
, -1, NULL
, NULL
, NULL
);
2378 icon
= g_themed_icon_new (name
);
2382 app
= g_hash_table_lookup (apps_by_exe
, appexe_folded_basename
);
2386 app
= g_object_new (G_TYPE_WIN32_APPINFO_APPLICATION
, NULL
);
2389 shell_open_command
? g_wcsdup (shell_open_command
, -1) : NULL
;
2391 if (shell_open_command
)
2392 app
->command_u8
= g_utf16_to_utf8 (shell_open_command
, -1, NULL
, NULL
, NULL
);
2394 app
->executable
= g_strdup (appexe
);
2395 app
->executable_basename
= &app
->executable
[appexe_basename
- appexe
];
2396 app
->executable_folded
= g_strdup (appexe_folded
);
2398 app
->no_open_with
= no_open_with
;
2400 if (friendly_app_name
)
2402 app
->localized_pretty_name
= g_wcsdup (friendly_app_name
, -1);
2403 g_clear_pointer (&app
->localized_pretty_name_u8
, g_free
);
2404 app
->localized_pretty_name_u8
=
2405 g_utf16_to_utf8 (friendly_app_name
, -1, NULL
, NULL
, NULL
);
2409 app
->icon
= g_object_ref (icon
);
2411 app
->user_specific
= FALSE
;
2412 app
->default_app
= FALSE
;
2414 g_hash_table_insert (apps_by_exe
,
2415 g_strdup (appexe_folded_basename
),
2420 g_win32_registry_key_get_child_w (incapable_app
,
2426 GWin32RegistryValueIter sup_iter
;
2427 if (g_win32_registry_value_iter_init (&sup_iter
, supported_key
, NULL
))
2429 gunichar2
*ext_name
;
2432 while (g_win32_registry_value_iter_next (&sup_iter
, TRUE
, NULL
))
2436 GWin32AppInfoFileExtension
*file_extn
;
2437 gboolean file_ext_known
;
2439 if ((!g_win32_registry_value_iter_get_name_w (&sup_iter
,
2443 (ext_name_len
<= 0) ||
2444 (ext_name
[0] != L
'.') ||
2445 (!utf8_and_fold (ext_name
,
2452 g_hash_table_lookup_extended (extensions
,
2455 (void **) &file_extn
);
2457 if (!file_ext_known
)
2460 g_object_new (G_TYPE_WIN32_APPINFO_FILE_EXTENSION
, NULL
);
2461 file_extn
->extension
= g_wcsdup (ext_name
, -1);
2462 file_extn
->extension_u8
= g_strdup (ext_u8
);
2463 g_hash_table_insert (extensions
,
2464 g_strdup (ext_folded
),
2468 g_hash_table_insert (file_extn
->other_apps
,
2469 g_strdup (appexe_folded
),
2470 g_object_ref (app
));
2473 g_free (ext_folded
);
2476 g_win32_registry_value_iter_clear (&sup_iter
);
2479 g_object_unref (supported_key
);
2484 g_free (appexe_folded
);
2485 g_free (shell_open_command
);
2486 g_free (friendly_app_name
);
2487 g_free (icon_source
);
2489 g_clear_object (&icon
);
2490 g_clear_object (&incapable_app
);
2493 g_win32_registry_subkey_iter_clear (&app_iter
);
2494 g_object_unref (applications_key
);
2499 read_exts (GWin32RegistryKey
*file_exts
)
2501 GWin32RegistrySubkeyIter ext_iter
;
2502 gunichar2
*file_extension
;
2503 gsize file_extension_len
;
2505 if (file_exts
== NULL
)
2508 if (!g_win32_registry_subkey_iter_init (&ext_iter
, file_exts
, NULL
))
2511 while (g_win32_registry_subkey_iter_next (&ext_iter
, TRUE
, NULL
))
2513 if (!g_win32_registry_subkey_iter_get_name_w (&ext_iter
,
2515 &file_extension_len
,
2519 get_file_ext (file_extension
);
2522 g_win32_registry_subkey_iter_clear (&ext_iter
);
2526 read_class_extension (GWin32RegistryKey
*classes_root
,
2527 gunichar2
*class_name
,
2528 gsize class_name_len
)
2532 GWin32AppInfoFileExtension
*file_extn
;
2533 GWin32AppInfoHandler
*handler_rec
;
2534 GWin32AppInfoHandler
*handler_rec_in_ext
;
2535 GWin32RegistryKey
*class_key
;
2536 gsize program_id_size
;
2537 gunichar2
*program_id
;
2538 gunichar2
*proxy_id
;
2539 GWin32RegistryKey
*program_key
;
2540 GWin32RegistryKey
*proxy_key
;
2541 gunichar2
*program_command
;
2542 gunichar2
*proxy_command
;
2544 class_key
= g_win32_registry_key_get_child_w (classes_root
, class_name
, NULL
);
2546 if (class_key
== NULL
)
2549 program_id
= class_name
;
2550 program_id_size
= (class_name_len
+ 1) * sizeof (gunichar2
);
2551 program_key
= proxy_key
= NULL
;
2552 program_command
= proxy_command
= NULL
;
2554 if (!follow_class_chain_to_handler (program_id
,
2564 g_object_unref (class_key
);
2569 file_extn
= g_hash_table_lookup (extensions
, ext_folded
);
2570 handler_rec
= g_hash_table_lookup (handlers
, ext_folded
);
2572 if (file_extn
== NULL
)
2574 file_extn
= g_object_new (G_TYPE_WIN32_APPINFO_FILE_EXTENSION
, NULL
);
2575 file_extn
->extension
= g_wcsdup (class_name
, -1);
2576 file_extn
->extension_u8
= g_strdup (ext_u8
);
2577 g_hash_table_insert (extensions
, g_strdup (ext_folded
), file_extn
);
2580 if (handler_rec
== NULL
)
2582 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
2584 handler_rec
->proxy_key
= proxy_key
;
2585 handler_rec
->key
= program_key
;
2586 handler_rec
->handler_id
= g_wcsdup (program_id
, program_id_size
);
2587 handler_rec
->handler_id_folded
= g_strdup (ext_folded
);
2588 handler_rec
->handler_command
=
2589 program_command
? g_wcsdup (program_command
, -1) : NULL
;
2590 handler_rec
->proxy_id
= proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
2591 handler_rec
->proxy_command
=
2592 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
2593 extract_executable (proxy_command
? proxy_command
: program_command
,
2594 &handler_rec
->executable
,
2595 &handler_rec
->executable_basename
,
2596 &handler_rec
->executable_folded
,
2598 read_handler_icon (proxy_key
, program_key
, &handler_rec
->icon
);
2599 g_hash_table_insert (handlers
,
2600 g_strdup (ext_folded
),
2605 g_clear_object (&program_key
);
2606 g_clear_object (&proxy_key
);
2609 handler_rec_in_ext
= g_hash_table_lookup (file_extn
->handlers
,
2612 if (file_extn
->chosen_handler
== NULL
)
2613 g_hash_table_insert (file_extn
->handlers
,
2614 g_strdup (ext_folded
),
2615 g_object_ref (handler_rec
));
2616 else if (handler_rec_in_ext
== NULL
)
2618 if (file_extn
->chosen_handler
->handler_id_folded
&&
2619 strcmp (file_extn
->chosen_handler
->handler_id_folded
,
2621 g_hash_table_insert (file_extn
->handlers
,
2622 g_strdup (ext_folded
),
2623 g_object_ref (handler_rec
));
2626 g_free (program_command
);
2628 g_free (proxy_command
);
2630 g_free (ext_folded
);
2631 g_object_unref (class_key
);
2635 read_class_url (GWin32RegistryKey
*classes_root
,
2636 gunichar2
*class_name
,
2637 gsize class_name_len
)
2639 GWin32RegistryKey
*class_key
;
2641 GWin32RegistryValueType vtype
;
2642 GWin32AppInfoURLSchema
*schema_rec
;
2643 GWin32AppInfoHandler
*handler_rec
;
2644 GWin32AppInfoHandler
*handler_rec_in_url
;
2645 gunichar2
*program_id
;
2646 gsize program_id_size
;
2647 gunichar2
*program_command
;
2648 gunichar2
*proxy_id
;
2649 gunichar2
*proxy_command
;
2650 gchar
*program_id_u8
;
2651 gchar
*program_id_folded
;
2652 GWin32RegistryKey
*program_key
;
2653 GWin32RegistryKey
*proxy_key
;
2655 class_key
= g_win32_registry_key_get_child_w (classes_root
, class_name
, NULL
);
2657 if (class_key
== NULL
)
2660 success
= g_win32_registry_key_get_value_w (class_key
,
2669 vtype
!= G_WIN32_REGISTRY_VALUE_STR
)
2671 g_object_unref (class_key
);
2675 program_id
= class_name
;
2676 program_id_size
= (class_name_len
+ 1) * sizeof (gunichar2
);
2677 proxy_key
= program_key
= NULL
;
2678 program_command
= proxy_id
= proxy_command
= NULL
;
2680 if (!follow_class_chain_to_handler (program_id
,
2688 &program_id_folded
))
2690 g_object_unref (class_key
);
2694 schema_rec
= g_hash_table_lookup (urls
, program_id_folded
);
2695 handler_rec
= g_hash_table_lookup (handlers
, program_id_folded
);
2697 if (handler_rec
== NULL
)
2699 handler_rec
= g_object_new (G_TYPE_WIN32_APPINFO_HANDLER
, NULL
);
2701 handler_rec
->proxy_key
= proxy_key
;
2702 handler_rec
->key
= program_key
;
2703 handler_rec
->handler_id
= g_wcsdup (program_id
, program_id_size
);
2704 handler_rec
->handler_id_folded
=
2705 g_strdup (program_id_folded
);
2706 handler_rec
->handler_command
=
2707 program_command
? g_wcsdup (program_command
, -1) : NULL
;
2708 handler_rec
->proxy_id
= proxy_id
? g_wcsdup (proxy_id
, -1) : NULL
;
2709 handler_rec
->proxy_command
=
2710 proxy_command
? g_wcsdup (proxy_command
, -1) : NULL
;
2711 extract_executable (proxy_command
? proxy_command
: program_command
,
2712 &handler_rec
->executable
,
2713 &handler_rec
->executable_basename
,
2714 &handler_rec
->executable_folded
,
2716 read_handler_icon (proxy_key
, program_key
, &handler_rec
->icon
);
2717 g_hash_table_insert (handlers
,
2718 g_strdup (program_id_folded
),
2723 g_clear_object (&program_key
);
2724 g_clear_object (&proxy_key
);
2727 if (schema_rec
== NULL
)
2729 schema_rec
= g_object_new (G_TYPE_WIN32_APPINFO_URL_SCHEMA
, NULL
);
2730 schema_rec
->schema
= g_wcsdup (class_name
, -1);
2731 schema_rec
->schema_u8
= g_strdup (program_id_u8
);
2732 schema_rec
->schema_folded
= g_strdup (program_id_folded
);
2733 schema_rec
->chosen_handler
= g_object_ref (handler_rec
);
2734 g_hash_table_insert (urls
,
2735 g_strdup (program_id_folded
),
2739 if (schema_rec
->chosen_handler
== NULL
)
2740 schema_rec
->chosen_handler
= g_object_ref (handler_rec
);
2742 handler_rec_in_url
= g_hash_table_lookup (schema_rec
->handlers
,
2745 if (handler_rec_in_url
== NULL
&& schema_rec
->chosen_handler
!= handler_rec
)
2746 g_hash_table_insert (schema_rec
->handlers
,
2747 g_strdup (program_id_folded
),
2748 g_object_ref (handler_rec
));
2750 g_free (program_id_u8
);
2751 g_free (program_id_folded
);
2752 g_free (program_command
);
2754 g_free (proxy_command
);
2755 g_object_unref (class_key
);
2759 read_classes (GWin32RegistryKey
*classes_root
)
2761 GWin32RegistrySubkeyIter class_iter
;
2762 gunichar2
*class_name
;
2763 gsize class_name_len
;
2765 if (classes_root
== NULL
)
2768 if (!g_win32_registry_subkey_iter_init (&class_iter
, classes_root
, NULL
))
2771 while (g_win32_registry_subkey_iter_next (&class_iter
, TRUE
, NULL
))
2773 if ((!g_win32_registry_subkey_iter_get_name_w (&class_iter
,
2777 (class_name_len
<= 1))
2780 if (class_name
[0] == L
'.')
2781 read_class_extension (classes_root
, class_name
, class_name_len
);
2786 for (i
= 0; i
< class_name_len
; i
++)
2787 if (!iswalpha (class_name
[i
]))
2790 if (i
== class_name_len
)
2791 read_class_url (classes_root
, class_name
, class_name_len
);
2795 g_win32_registry_subkey_iter_clear (&class_iter
);
2799 link_chosen_handlers (void)
2801 GHashTableIter iter
;
2802 GHashTableIter handler_iter
;
2803 gchar
*schema_folded
;
2804 GWin32AppInfoURLSchema
*schema
;
2805 gchar
*handler_id_folded
;
2806 GWin32AppInfoHandler
*handler
;
2808 GWin32AppInfoFileExtension
*ext
;
2810 g_hash_table_iter_init (&iter
, urls
);
2812 while (g_hash_table_iter_next (&iter
,
2813 (gpointer
*) &schema_folded
,
2814 (gpointer
*) &schema
))
2816 if (schema
->chosen_handler
!= NULL
)
2819 g_hash_table_iter_init (&handler_iter
, schema
->handlers
);
2821 while (g_hash_table_iter_next (&handler_iter
,
2822 (gpointer
*) &handler_id_folded
,
2823 (gpointer
*) &handler
))
2825 gchar
*proxy_id_folded
;
2827 if (schema
->chosen_handler
!= NULL
)
2830 if (strcmp (handler_id_folded
, schema_folded
) != 0)
2833 if (handler
->proxy_command
&&
2834 handler
->proxy_id
&&
2835 utf8_and_fold (handler
->proxy_id
,
2839 GWin32AppInfoHandler
*proxy
;
2841 proxy
= g_hash_table_lookup (handlers
, proxy_id_folded
);
2845 schema
->chosen_handler
= g_object_ref (proxy
);
2846 g_debug ("Linking schema %s to proxy handler %c ? \"%S\" : %S\n",
2848 schema
->chosen_handler
->proxy_id
? 'P' : 'T',
2849 schema
->chosen_handler
->proxy_id
? schema
->chosen_handler
->proxy_id
: schema
->chosen_handler
->handler_id
,
2850 schema
->chosen_handler
->proxy_command
? schema
->chosen_handler
->proxy_command
: schema
->chosen_handler
->handler_command
);
2853 g_free (proxy_id_folded
);
2856 if (schema
->chosen_handler
== NULL
)
2858 schema
->chosen_handler
= g_object_ref (handler
);
2859 g_debug ("Linking schema %s to handler %c ? \"%S\" : %S\n",
2861 schema
->chosen_handler
->proxy_id
? 'P' : 'T',
2862 schema
->chosen_handler
->proxy_id
? schema
->chosen_handler
->proxy_id
: schema
->chosen_handler
->handler_id
,
2863 schema
->chosen_handler
->proxy_command
? schema
->chosen_handler
->proxy_command
: schema
->chosen_handler
->handler_command
);
2868 g_hash_table_iter_init (&iter
, extensions
);
2870 while (g_hash_table_iter_next (&iter
,
2871 (gpointer
*) &ext_folded
,
2874 if (ext
->chosen_handler
!= NULL
)
2877 g_hash_table_iter_init (&handler_iter
, ext
->handlers
);
2879 while (g_hash_table_iter_next (&handler_iter
,
2880 (gpointer
*) &handler_id_folded
,
2881 (gpointer
*) &handler
))
2883 gchar
*proxy_id_folded
;
2885 if (ext
->chosen_handler
!= NULL
)
2888 if (strcmp (handler_id_folded
, ext_folded
) != 0)
2891 if (handler
->proxy_command
&&
2892 handler
->proxy_id
&&
2893 utf8_and_fold (handler
->proxy_id
,
2897 GWin32AppInfoHandler
*proxy
;
2899 proxy
= g_hash_table_lookup (handlers
, proxy_id_folded
);
2903 ext
->chosen_handler
= g_object_ref (proxy
);
2904 g_debug ("Linking ext %s to proxy handler %c ? \"%S\" : %S\n",
2906 ext
->chosen_handler
->proxy_id
? 'P' : 'T',
2907 ext
->chosen_handler
->proxy_id
? ext
->chosen_handler
->proxy_id
: ext
->chosen_handler
->handler_id
,
2908 ext
->chosen_handler
->proxy_command
? ext
->chosen_handler
->proxy_command
: ext
->chosen_handler
->handler_command
);
2911 g_free (proxy_id_folded
);
2914 if (ext
->chosen_handler
== NULL
)
2916 ext
->chosen_handler
= g_object_ref (handler
);
2917 g_debug ("Linking ext %s to handler %c ? \"%S\" : %S\n",
2919 ext
->chosen_handler
->proxy_id
? 'P' : 'T',
2920 ext
->chosen_handler
->proxy_id
? ext
->chosen_handler
->proxy_id
: ext
->chosen_handler
->handler_id
,
2921 ext
->chosen_handler
->proxy_command
? ext
->chosen_handler
->proxy_command
: ext
->chosen_handler
->handler_command
);
2928 link_handlers_to_registered_apps (void)
2930 GHashTableIter iter
;
2931 GHashTableIter sup_iter
;
2932 gchar
*app_id_folded
;
2933 GWin32AppInfoApplication
*app
;
2934 gchar
*schema_folded
;
2935 GWin32AppInfoURLSchema
*schema
;
2937 GWin32AppInfoFileExtension
*ext
;
2938 gsize unhandled_exts
;
2940 g_hash_table_iter_init (&sup_iter
, urls
);
2941 while (g_hash_table_iter_next (&sup_iter
,
2942 (gpointer
*) &schema_folded
,
2943 (gpointer
*) &schema
))
2945 if (schema
->chosen_handler
== NULL
)
2946 g_debug ("WARNING: schema %s has no chosen handler\n", schema
->schema_u8
);
2949 g_hash_table_iter_init (&sup_iter
, extensions
);
2950 while (g_hash_table_iter_next (&sup_iter
,
2951 (gpointer
*) &ext_folded
,
2954 if (ext
->chosen_handler
== NULL
)
2956 g_debug ("WARNING: extension %s has no chosen handler\n",
2958 unhandled_exts
+= 1;
2962 g_hash_table_iter_init (&iter
, apps_by_id
);
2963 while (g_hash_table_iter_next (&iter
,
2964 (gpointer
*) &app_id_folded
,
2967 if (app
->supported_urls
)
2969 GWin32AppInfoHandler
*handler
;
2971 g_hash_table_iter_init (&sup_iter
, app
->supported_urls
);
2972 while (g_hash_table_iter_next (&sup_iter
,
2973 (gpointer
*) &schema_folded
,
2974 (gpointer
*) &handler
))
2976 schema
= g_hash_table_lookup (urls
, schema_folded
);
2978 g_assert (schema
!= NULL
);
2980 if (schema
->chosen_handler
!= NULL
&&
2981 schema
->chosen_handler
->app
== NULL
)
2983 schema
->chosen_handler
->app
= g_object_ref (app
);
2984 g_debug ("Linking %S", app
->canonical_name
);
2986 if (app
->localized_pretty_name
)
2987 g_debug (" '%S'", app
->localized_pretty_name
);
2988 else if (app
->pretty_name
)
2989 g_debug (" '%S'", app
->pretty_name
);
2991 g_debug (" '%s'", app
->executable
);
2994 g_debug (" %S", app
->command
);
2996 g_debug ("\n to schema %s handler %c ? \"%S\" : %S\n",
2998 schema
->chosen_handler
->proxy_id
? 'P' : 'T',
2999 schema
->chosen_handler
->proxy_id
? schema
->chosen_handler
->proxy_id
: schema
->chosen_handler
->handler_id
,
3000 schema
->chosen_handler
->proxy_command
? schema
->chosen_handler
->proxy_command
: schema
->chosen_handler
->handler_command
);
3004 g_hash_table_iter_init (&sup_iter
, app
->supported_urls
);
3005 while (g_hash_table_iter_next (&sup_iter
,
3006 (gpointer
*) &schema_folded
,
3007 (gpointer
*) &handler
))
3009 if (handler
->app
== NULL
)
3011 handler
->app
= g_object_ref (app
);
3012 g_debug ("Linking %S", app
->canonical_name
);
3014 if (app
->localized_pretty_name
)
3015 g_debug (" '%S'", app
->localized_pretty_name
);
3016 else if (app
->pretty_name
)
3017 g_debug (" '%S'", app
->pretty_name
);
3019 g_debug (" '%s'", app
->executable
);
3022 g_debug (" %S", app
->command
);
3024 g_debug ("\n directly to schema handler to %c ? \"%S\" : %S\n",
3025 handler
->proxy_id
? 'P' : 'T',
3026 handler
->proxy_id
? handler
->proxy_id
: handler
->handler_id
,
3027 handler
->proxy_command
? handler
->proxy_command
: handler
->handler_command
);
3032 if (app
->supported_exts
)
3034 GWin32AppInfoHandler
*handler
;
3036 g_hash_table_iter_init (&sup_iter
, app
->supported_exts
);
3037 while (g_hash_table_iter_next (&sup_iter
,
3038 (gpointer
*) &ext_folded
,
3039 (gpointer
*) &handler
))
3041 ext
= g_hash_table_lookup (extensions
, ext_folded
);
3043 g_assert (ext
!= NULL
);
3045 if (ext
->chosen_handler
!= NULL
&&
3046 ext
->chosen_handler
->app
== NULL
)
3048 ext
->chosen_handler
->app
= g_object_ref (app
);
3049 g_debug ("Linking %S", app
->canonical_name
);
3051 if (app
->localized_pretty_name
)
3052 g_debug (" '%S'", app
->localized_pretty_name
);
3053 else if (app
->pretty_name
)
3054 g_debug (" '%S'", app
->pretty_name
);
3056 g_debug (" '%s'", app
->executable
);
3059 g_debug (" %S", app
->command
);
3061 g_debug ("\n to ext %s handler %c ? \"%S\" : %S\n",
3063 ext
->chosen_handler
->proxy_id
? 'P' : 'T',
3064 ext
->chosen_handler
->proxy_id
? ext
->chosen_handler
->proxy_id
: ext
->chosen_handler
->handler_id
,
3065 ext
->chosen_handler
->proxy_command
? ext
->chosen_handler
->proxy_command
: ext
->chosen_handler
->handler_command
);
3069 g_hash_table_iter_init (&sup_iter
, app
->supported_exts
);
3070 while (g_hash_table_iter_next (&sup_iter
,
3071 (gpointer
*) &ext_folded
,
3072 (gpointer
*) &handler
))
3074 if (handler
->app
== NULL
)
3076 handler
->app
= g_object_ref (app
);
3077 g_debug ("Linking %S", app
->canonical_name
);
3079 if (app
->localized_pretty_name
)
3080 g_debug (" '%S'", app
->localized_pretty_name
);
3081 else if (app
->pretty_name
)
3082 g_debug (" '%S'", app
->pretty_name
);
3084 g_debug (" '%s'", app
->executable
);
3087 g_debug (" %S", app
->command
);
3089 g_debug ("\n directly to ext handler %c ? \"%S\" : %S\n",
3090 handler
->proxy_id
? 'P' : 'T',
3091 handler
->proxy_id
? handler
->proxy_id
: handler
->handler_id
,
3092 handler
->proxy_command
? handler
->proxy_command
: handler
->handler_command
);
3098 g_debug ("%" G_GSIZE_FORMAT
"undefhandled extensions\n", unhandled_exts
);
3100 g_hash_table_iter_init (&sup_iter
, extensions
);
3101 while (g_hash_table_iter_next (&sup_iter
,
3102 (gpointer
*) &ext_folded
,
3105 if (ext
->chosen_handler
== NULL
)
3107 g_debug ("WARNING: extension %s has no chosen handler\n",
3109 unhandled_exts
+= 1;
3112 g_debug ("%" G_GSIZE_FORMAT
"undefhandled extensions\n", unhandled_exts
);
3116 link_handlers_to_unregistered_apps (void)
3118 GHashTableIter iter
;
3119 GHashTableIter app_iter
;
3120 GWin32AppInfoHandler
*handler
;
3121 gchar
*handler_id_fc
;
3122 GWin32AppInfoApplication
*app
;
3123 gchar
*canonical_name_fc
;
3124 gchar
*appexe_fc_basename
;
3126 g_hash_table_iter_init (&iter
, handlers
);
3127 while (g_hash_table_iter_next (&iter
,
3128 (gpointer
*) &handler_id_fc
,
3129 (gpointer
*) &handler
))
3131 gchar
*hndexe_fc_basename
;
3133 if ((handler
->app
!= NULL
) ||
3134 (handler
->executable_folded
== NULL
))
3137 hndexe_fc_basename
= g_utf8_casefold (handler
->executable_basename
, -1);
3139 if (hndexe_fc_basename
== NULL
)
3142 g_hash_table_iter_init (&app_iter
, apps_by_id
);
3144 while (g_hash_table_iter_next (&app_iter
,
3145 (gpointer
*) &canonical_name_fc
,
3148 if (app
->executable_folded
== NULL
)
3151 if (strcmp (app
->executable_folded
,
3152 handler
->executable_folded
) != 0)
3159 if (handler
->app
!= NULL
)
3162 g_hash_table_iter_init (&app_iter
, apps_by_exe
);
3164 while ((hndexe_fc_basename
!= NULL
) &&
3165 (g_hash_table_iter_next (&app_iter
,
3166 (gpointer
*) &appexe_fc_basename
,
3167 (gpointer
*) &app
)))
3169 /* Use basename because apps_by_exe only has basenames */
3170 if (strcmp (hndexe_fc_basename
, appexe_fc_basename
) != 0)
3177 g_free (hndexe_fc_basename
);
3179 if (handler
->app
== NULL
)
3180 g_debug ("WARNING: handler that runs %s has no corresponding app\n",
3181 handler
->executable
);
3187 update_registry_data (void)
3190 GPtrArray
*capable_apps_keys
;
3191 GPtrArray
*user_capable_apps_keys
;
3192 GPtrArray
*priority_capable_apps_keys
;
3193 GWin32RegistryKey
*url_associations
;
3194 GWin32RegistryKey
*file_exts
;
3195 GWin32RegistryKey
*classes_root
;
3196 DWORD collect_start
, collect_end
, alloc_end
, capable_end
, url_end
, ext_end
, exeapp_end
, classes_end
, postproc_end
;
3199 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations",
3202 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts",
3204 classes_root
= g_win32_registry_key_new_w (L
"HKEY_CLASSES_ROOT", NULL
);
3206 capable_apps_keys
= g_ptr_array_new_with_free_func (g_free
);
3207 user_capable_apps_keys
= g_ptr_array_new_with_free_func (g_free
);
3208 priority_capable_apps_keys
= g_ptr_array_new_with_free_func (g_free
);
3210 g_clear_pointer (&apps_by_id
, g_hash_table_destroy
);
3211 g_clear_pointer (&apps_by_exe
, g_hash_table_destroy
);
3212 g_clear_pointer (&urls
, g_hash_table_destroy
);
3213 g_clear_pointer (&extensions
, g_hash_table_destroy
);
3214 g_clear_pointer (&handlers
, g_hash_table_destroy
);
3216 collect_start
= GetTickCount ();
3217 collect_capable_apps_from_clients (capable_apps_keys
,
3218 priority_capable_apps_keys
,
3220 collect_capable_apps_from_clients (user_capable_apps_keys
,
3221 priority_capable_apps_keys
,
3223 collect_capable_apps_from_registered_apps (user_capable_apps_keys
,
3225 collect_capable_apps_from_registered_apps (capable_apps_keys
,
3227 collect_end
= GetTickCount ();
3230 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
3232 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
3234 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
3236 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
3238 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
3239 alloc_end
= GetTickCount ();
3241 for (i
= 0; i
< priority_capable_apps_keys
->len
; i
++)
3242 read_capable_app (g_ptr_array_index (priority_capable_apps_keys
, i
),
3245 for (i
= 0; i
< user_capable_apps_keys
->len
; i
++)
3246 read_capable_app (g_ptr_array_index (user_capable_apps_keys
, i
),
3249 for (i
= 0; i
< capable_apps_keys
->len
; i
++)
3250 read_capable_app (g_ptr_array_index (capable_apps_keys
, i
),
3253 capable_end
= GetTickCount ();
3255 read_urls (url_associations
);
3256 url_end
= GetTickCount ();
3257 read_exts (file_exts
);
3258 ext_end
= GetTickCount ();
3260 exeapp_end
= GetTickCount ();
3261 read_classes (classes_root
);
3262 classes_end
= GetTickCount ();
3263 link_chosen_handlers ();
3264 link_handlers_to_registered_apps ();
3265 link_handlers_to_unregistered_apps ();
3266 postproc_end
= GetTickCount ();
3268 g_debug ("Collecting capable appnames: %lums\n"
3269 "Allocating hashtables:...... %lums\n"
3270 "Reading capable apps: %lums\n"
3271 "Reading URL associations:... %lums\n"
3272 "Reading extension assocs: %lums\n"
3273 "Reading exe-only apps:...... %lums\n"
3274 "Reading classes: %lums\n"
3275 "Postprocessing:..............%lums\n"
3277 collect_end
- collect_start
,
3278 alloc_end
- collect_end
,
3279 capable_end
- alloc_end
,
3280 url_end
- capable_end
,
3282 exeapp_end
- ext_end
,
3283 classes_end
- exeapp_end
,
3284 postproc_end
- classes_end
,
3285 postproc_end
- collect_start
);
3287 g_clear_object (&classes_root
);
3288 g_clear_object (&url_associations
);
3289 g_clear_object (&file_exts
);
3290 g_ptr_array_free (capable_apps_keys
, TRUE
);
3291 g_ptr_array_free (user_capable_apps_keys
, TRUE
);
3292 g_ptr_array_free (priority_capable_apps_keys
, TRUE
);
3300 if (url_associations_key
)
3301 g_win32_registry_key_watch (url_associations_key
,
3303 G_WIN32_REGISTRY_WATCH_NAME
|
3304 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3305 G_WIN32_REGISTRY_WATCH_VALUES
,
3311 g_win32_registry_key_watch (file_exts_key
,
3313 G_WIN32_REGISTRY_WATCH_NAME
|
3314 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3315 G_WIN32_REGISTRY_WATCH_VALUES
,
3320 if (user_clients_key
)
3321 g_win32_registry_key_watch (user_clients_key
,
3323 G_WIN32_REGISTRY_WATCH_NAME
|
3324 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3325 G_WIN32_REGISTRY_WATCH_VALUES
,
3330 if (system_clients_key
)
3331 g_win32_registry_key_watch (system_clients_key
,
3333 G_WIN32_REGISTRY_WATCH_NAME
|
3334 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3335 G_WIN32_REGISTRY_WATCH_VALUES
,
3340 if (applications_key
)
3341 g_win32_registry_key_watch (applications_key
,
3343 G_WIN32_REGISTRY_WATCH_NAME
|
3344 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3345 G_WIN32_REGISTRY_WATCH_VALUES
,
3350 if (user_registered_apps_key
)
3351 g_win32_registry_key_watch (user_registered_apps_key
,
3353 G_WIN32_REGISTRY_WATCH_NAME
|
3354 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3355 G_WIN32_REGISTRY_WATCH_VALUES
,
3360 if (system_registered_apps_key
)
3361 g_win32_registry_key_watch (system_registered_apps_key
,
3363 G_WIN32_REGISTRY_WATCH_NAME
|
3364 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3365 G_WIN32_REGISTRY_WATCH_VALUES
,
3370 if (classes_root_key
)
3371 g_win32_registry_key_watch (classes_root_key
,
3373 G_WIN32_REGISTRY_WATCH_NAME
|
3374 G_WIN32_REGISTRY_WATCH_ATTRIBUTES
|
3375 G_WIN32_REGISTRY_WATCH_VALUES
,
3383 g_win32_appinfo_init (void)
3385 static gsize initialized
;
3387 if (g_once_init_enter (&initialized
))
3389 url_associations_key
=
3390 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations",
3393 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts",
3396 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\Clients",
3398 system_clients_key
=
3399 g_win32_registry_key_new_w (L
"HKEY_LOCAL_MACHINE\\Software\\Clients",
3402 g_win32_registry_key_new_w (L
"HKEY_CLASSES_ROOT\\Applications",
3404 user_registered_apps_key
=
3405 g_win32_registry_key_new_w (L
"HKEY_CURRENT_USER\\Software\\RegisteredApplications",
3407 system_registered_apps_key
=
3408 g_win32_registry_key_new_w (L
"HKEY_LOCAL_MACHINE\\Software\\RegisteredApplications",
3411 g_win32_registry_key_new_w (L
"HKEY_CLASSES_ROOT",
3416 update_registry_data ();
3418 g_once_init_leave (&initialized
, TRUE
);
3421 if ((url_associations_key
&& g_win32_registry_key_has_changed (url_associations_key
)) ||
3422 (file_exts_key
&& g_win32_registry_key_has_changed (file_exts_key
)) ||
3423 (user_clients_key
&& g_win32_registry_key_has_changed (user_clients_key
)) ||
3424 (system_clients_key
&& g_win32_registry_key_has_changed (system_clients_key
)) ||
3425 (applications_key
&& g_win32_registry_key_has_changed (applications_key
)) ||
3426 (user_registered_apps_key
&& g_win32_registry_key_has_changed (user_registered_apps_key
)) ||
3427 (system_registered_apps_key
&& g_win32_registry_key_has_changed (system_registered_apps_key
)) ||
3428 (classes_root_key
&& g_win32_registry_key_has_changed (classes_root_key
)))
3430 G_LOCK (gio_win32_appinfo
);
3431 update_registry_data ();
3433 G_UNLOCK (gio_win32_appinfo
);
3438 static void g_win32_app_info_iface_init (GAppInfoIface
*iface
);
3440 struct _GWin32AppInfo
3442 GObject parent_instance
;
3445 gchar
**supported_types
;
3447 GWin32AppInfoApplication
*app
;
3449 GWin32AppInfoHandler
*handler
;
3451 guint startup_notify
: 1;
3454 G_DEFINE_TYPE_WITH_CODE (GWin32AppInfo
, g_win32_app_info
, G_TYPE_OBJECT
,
3455 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO
,
3456 g_win32_app_info_iface_init
))
3460 g_win32_app_info_finalize (GObject
*object
)
3462 GWin32AppInfo
*info
;
3464 info
= G_WIN32_APP_INFO (object
);
3466 g_clear_pointer (&info
->supported_types
, g_free
);
3467 g_clear_object (&info
->app
);
3468 g_clear_object (&info
->handler
);
3470 G_OBJECT_CLASS (g_win32_app_info_parent_class
)->finalize (object
);
3474 g_win32_app_info_class_init (GWin32AppInfoClass
*klass
)
3476 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
3478 gobject_class
->finalize
= g_win32_app_info_finalize
;
3482 g_win32_app_info_init (GWin32AppInfo
*local
)
3487 g_win32_app_info_new_from_app (GWin32AppInfoApplication
*app
,
3488 GWin32AppInfoHandler
*handler
)
3490 GWin32AppInfo
*new_info
;
3491 GHashTableIter iter
;
3495 new_info
= g_object_new (G_TYPE_WIN32_APP_INFO
, NULL
);
3497 new_info
->app
= g_object_ref (app
);
3499 g_win32_appinfo_init ();
3500 G_LOCK (gio_win32_appinfo
);
3503 g_hash_table_iter_init (&iter
, new_info
->app
->supported_exts
);
3505 while (g_hash_table_iter_next (&iter
, &ext
, NULL
))
3511 new_info
->supported_types
= g_malloc (sizeof (gchar
*) * (i
+ 1));
3514 g_hash_table_iter_init (&iter
, new_info
->app
->supported_exts
);
3516 while (g_hash_table_iter_next (&iter
, &ext
, NULL
))
3521 new_info
->supported_types
[i
] = (gchar
*) ext
;
3525 G_UNLOCK (gio_win32_appinfo
);
3527 new_info
->supported_types
[i
] = NULL
;
3529 new_info
->handler
= handler
? g_object_ref (handler
) : NULL
;
3531 return G_APP_INFO (new_info
);
3536 g_win32_app_info_dup (GAppInfo
*appinfo
)
3538 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3539 GWin32AppInfo
*new_info
;
3541 new_info
= g_object_new (G_TYPE_WIN32_APP_INFO
, NULL
);
3544 new_info
->app
= g_object_ref (info
->app
);
3547 new_info
->handler
= g_object_ref (info
->handler
);
3549 new_info
->startup_notify
= info
->startup_notify
;
3551 if (info
->supported_types
)
3555 for (i
= 0; info
->supported_types
[i
]; i
++)
3558 new_info
->supported_types
= g_malloc (sizeof (gchar
*) * (i
+ 1));
3560 for (i
= 0; info
->supported_types
[i
]; i
++)
3561 new_info
->supported_types
[i
] = g_strdup (info
->supported_types
[i
]);
3563 new_info
->supported_types
[i
] = NULL
;
3566 return G_APP_INFO (new_info
);
3570 g_win32_app_info_equal (GAppInfo
*appinfo1
,
3573 GWin32AppInfo
*info1
= G_WIN32_APP_INFO (appinfo1
);
3574 GWin32AppInfo
*info2
= G_WIN32_APP_INFO (appinfo2
);
3576 if (info1
->app
== NULL
||
3578 return info1
== info2
;
3580 if (info1
->app
->canonical_name_folded
!= NULL
&&
3581 info2
->app
->canonical_name_folded
!= NULL
)
3582 return (strcmp (info1
->app
->canonical_name_folded
,
3583 info2
->app
->canonical_name_folded
)) == 0;
3585 if (info1
->app
->executable_folded
!= NULL
&&
3586 info2
->app
->executable_folded
!= NULL
)
3587 return (strcmp (info1
->app
->executable_folded
,
3588 info2
->app
->executable_folded
)) == 0;
3590 return info1
->app
== info2
->app
;
3594 g_win32_app_info_get_id (GAppInfo
*appinfo
)
3596 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3598 if (info
->app
== NULL
)
3601 if (info
->app
->canonical_name_u8
)
3602 return info
->app
->canonical_name_u8
;
3604 if (info
->app
->executable_basename
)
3605 return info
->app
->executable_basename
;
3611 g_win32_app_info_get_name (GAppInfo
*appinfo
)
3613 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3615 if (info
->app
&& info
->app
->canonical_name_u8
)
3616 return info
->app
->canonical_name_u8
;
3618 return P_("Unnamed");
3622 g_win32_app_info_get_display_name (GAppInfo
*appinfo
)
3624 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3628 if (info
->app
->localized_pretty_name_u8
)
3629 return info
->app
->localized_pretty_name_u8
;
3630 else if (info
->app
->pretty_name_u8
)
3631 return info
->app
->pretty_name_u8
;
3634 return g_win32_app_info_get_name (appinfo
);
3638 g_win32_app_info_get_description (GAppInfo
*appinfo
)
3640 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3642 if (info
->app
== NULL
)
3645 return info
->app
->description_u8
;
3649 g_win32_app_info_get_executable (GAppInfo
*appinfo
)
3651 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3653 if (info
->app
== NULL
)
3656 return info
->app
->executable
;
3660 g_win32_app_info_get_commandline (GAppInfo
*appinfo
)
3662 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3664 if (info
->app
== NULL
)
3667 return info
->app
->command_u8
;
3671 g_win32_app_info_get_icon (GAppInfo
*appinfo
)
3673 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
3675 if (info
->app
== NULL
)
3678 return info
->app
->icon
;
3681 typedef struct _file_or_uri
{
3687 expand_macro_single (char macro
, file_or_uri
*obj
)
3689 char *result
= NULL
;
3706 /* TODO: handle 'l' and 'd' differently (longname and desktop name) */
3708 result
= g_strdup (obj
->uri
);
3710 result
= g_strdup (obj
->file
);
3715 result
= g_shell_quote (obj
->uri
);
3720 result
= g_shell_quote (obj
->file
);
3728 expand_macro (char macro
,
3730 GWin32AppInfo
*info
,
3731 GList
**stat_obj_list
,
3734 GList
*objs
= *obj_list
;
3736 gboolean result
= FALSE
;
3738 g_return_val_if_fail (exec
!= NULL
, FALSE
);
3741 Legend: (from http://msdn.microsoft.com/en-us/library/windows/desktop/cc144101%28v=vs.85%29.aspx)
3742 %* - replace with all parameters
3743 %~ - replace with all parameters starting with and following the second parameter
3744 %0 or %1 the first file parameter. For example "C:\\Users\\Eric\\Destop\\New Text Document.txt". Generally this should be in quotes and the applications command line parsing should accept quotes to disambiguate files with spaces in the name and different command line parameters (this is a security best practice and I believe mentioned in MSDN).
3745 %<n> (where N is 2 - 9), replace with the nth parameter
3748 %i - IDList stored in a shared memory handle is passed here.
3749 %l - long file name form of the first parameter. Note win32 applications will be passed the long file name, win16 applications get the short file name. Specifying %L is preferred as it avoids the need to probe for the application type.
3750 %d - desktop absolute parsing name of the first parameter (for items that don't have file system paths)
3751 %v - for verbs that are none implies all, if there is no parameter passed this is the working directory
3752 %w - the working directory
3764 for (o
= *stat_obj_list
, i
= 0;
3765 macro
== '~' && o
&& i
< 2;
3768 for (; o
; o
= o
->next
)
3770 expanded
= expand_macro_single (macro
, o
->data
);
3774 if (o
!= *stat_obj_list
)
3775 g_string_append (exec
, " ");
3777 g_string_append (exec
, expanded
);
3798 expanded
= expand_macro_single (macro
, o
->data
);
3802 if (o
!= *stat_obj_list
)
3803 g_string_append (exec
, " ");
3805 g_string_append (exec
, expanded
);
3858 for (o
= *stat_obj_list
, i
= 0; o
&& i
< n
; o
= o
->next
, i
++);
3862 expanded
= expand_macro_single (macro
, o
->data
);
3866 if (o
!= *stat_obj_list
)
3867 g_string_append (exec
, " ");
3869 g_string_append (exec
, expanded
);
3888 expanded
= g_get_current_dir ();
3889 g_string_append (exec
, expanded
);
3896 expanded
= expand_macro_single (macro
, objs
->data
);
3900 g_string_append (exec
, expanded
);
3913 expanded
= expand_macro_single (macro
, objs
->data
);
3917 g_string_append (exec
, expanded
);
3924 if (objs
!= NULL
&& expanded
)
3925 g_string_append_c (exec
, ' ');
3931 if (info
->app
&& info
->app
->localized_pretty_name_u8
)
3933 expanded
= g_shell_quote (info
->app
->localized_pretty_name_u8
);
3934 g_string_append (exec
, expanded
);
3939 case 'm': /* deprecated */
3940 case 'n': /* deprecated */
3941 case 'N': /* deprecated */
3942 /*case 'd': *//* deprecated */
3943 case 'D': /* deprecated */
3947 g_string_append_c (exec
, '%');
3957 expand_application_parameters (GWin32AppInfo
*info
,
3958 const gchar
*exec_line
,
3964 GList
*obj_list
= *objs
;
3965 GList
**stat_obj_list
= objs
;
3966 const char *p
= exec_line
;
3967 GString
*expanded_exec
;
3971 if (exec_line
== NULL
)
3973 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
3974 P_("Application registry did not specify"
3975 " a shell\\open\\command"));
3979 expanded_exec
= g_string_new (NULL
);
3984 if (p
[0] == '%' && p
[1] != '\0')
3986 if (expand_macro (p
[1],
3988 info
, stat_obj_list
,
3995 g_string_append_c (expanded_exec
, *p
);
4000 /* No file substitutions */
4001 if (obj_list
== *objs
&& obj_list
!= NULL
&& !res
)
4003 /* If there is no macro default to %f. This is also what KDE does */
4004 g_string_append_c (expanded_exec
, ' ');
4005 expand_macro ('f', expanded_exec
, info
, stat_obj_list
, objs
);
4008 /* Replace '\\' with '/', because g_shell_parse_argv considers them
4009 * to be escape sequences.
4011 for (a_char
= expanded_exec
->str
;
4012 a_char
<= &expanded_exec
->str
[expanded_exec
->len
];
4015 if (*a_char
== '\\')
4019 res
= g_shell_parse_argv (expanded_exec
->str
, argc
, argv
, error
);
4020 g_string_free (expanded_exec
, TRUE
);
4026 get_appath_for_exe (gunichar2
*exe_basename
)
4028 GWin32RegistryKey
*apppath_key
= NULL
;
4029 GWin32RegistryValueType val_type
;
4030 gunichar2
*appath
= NULL
;
4032 gchar
*result
= NULL
;
4034 apppath_key
= _g_win32_registry_key_build_and_new_w (NULL
, L
"HKEY_LOCAL_MACHINE\\"
4040 exe_basename
, NULL
);
4042 if (apppath_key
== NULL
)
4045 got_value
= g_win32_registry_key_get_value_w (apppath_key
,
4053 g_object_unref (apppath_key
);
4055 if (got_value
&& val_type
== G_WIN32_REGISTRY_VALUE_STR
)
4056 result
= g_utf16_to_utf8 (appath
, -1, NULL
,NULL
, NULL
);
4058 g_clear_pointer (&appath
, g_free
);
4065 g_win32_app_info_launch_internal (GWin32AppInfo
*info
,
4067 GAppLaunchContext
*launch_context
,
4068 GSpawnFlags spawn_flags
,
4071 gboolean completed
= FALSE
;
4072 char **argv
, **envp
;
4076 gunichar2
*exe_basename
;
4078 g_return_val_if_fail (info
!= NULL
, FALSE
);
4079 g_return_val_if_fail (info
->app
!= NULL
, FALSE
);
4084 envp
= g_app_launch_context_get_environment (launch_context
);
4086 envp
= g_get_environ ();
4089 exe_basename
= NULL
;
4093 if (info
->handler
->handler_command
)
4095 command
= g_utf16_to_utf8 (info
->handler
->handler_command
,
4100 exe_basename
= g_utf8_to_utf16 (info
->handler
->executable_basename
,
4106 else if (info
->handler
->proxy_command
)
4108 command
= g_utf16_to_utf8 (info
->handler
->proxy_command
,
4113 exe_basename
= g_utf8_to_utf16 (info
->handler
->executable_basename
,
4121 if (command
== NULL
)
4123 command
= g_strdup (info
->app
->command_u8
);
4124 exe_basename
= g_utf8_to_utf16 (info
->app
->executable_basename
,
4131 apppath
= get_appath_for_exe (exe_basename
);
4133 g_free (exe_basename
);
4140 for (p
= envp
, p_index
= 0; p
[0]; p
++, p_index
++)
4141 if ((p
[0][0] == 'p' || p
[0][0] == 'P') &&
4142 (p
[0][1] == 'a' || p
[0][1] == 'A') &&
4143 (p
[0][2] == 't' || p
[0][2] == 'T') &&
4144 (p
[0][3] == 'h' || p
[0][3] == 'H') &&
4151 new_envp
= g_new (char *, g_strv_length (envp
) + 2);
4152 new_envp
[0] = g_strdup_printf ("PATH=%s", apppath
);
4154 for (p_index
= 0; p_index
<= g_strv_length (envp
); p_index
++)
4155 new_envp
[1 + p_index
] = envp
[p_index
];
4166 if (p_path
[0] != '\0')
4167 envp
[p_index
] = g_strdup_printf ("PATH=%s%c%s",
4169 G_SEARCHPATH_SEPARATOR
,
4172 envp
[p_index
] = g_strdup_printf ("PATH=%s", apppath
);
4174 g_free (&p_path
[-5]);
4182 if (!expand_application_parameters (info
,
4190 if (!g_spawn_async (NULL
,
4200 if (launch_context
!= NULL
)
4202 GVariantBuilder builder
;
4203 GVariant
*platform_data
;
4205 g_variant_builder_init (&builder
, G_VARIANT_TYPE_ARRAY
);
4206 g_variant_builder_add (&builder
, "{sv}", "pid", g_variant_new_int32 ((gint32
) pid
));
4208 platform_data
= g_variant_ref_sink (g_variant_builder_end (&builder
));
4209 g_signal_emit_by_name (launch_context
, "launched", info
, platform_data
);
4210 g_variant_unref (platform_data
);
4216 while (objs
!= NULL
);
4229 free_file_or_uri (gpointer ptr
)
4231 file_or_uri
*obj
= ptr
;
4239 g_win32_app_supports_uris (GWin32AppInfoApplication
*app
)
4241 gssize num_of_uris_supported
;
4246 num_of_uris_supported
= (gssize
) g_hash_table_size (app
->supported_urls
);
4248 if (g_hash_table_lookup (app
->supported_urls
, "file"))
4249 num_of_uris_supported
-= 1;
4251 return num_of_uris_supported
> 0;
4256 g_win32_app_info_supports_uris (GAppInfo
*appinfo
)
4258 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
4260 if (info
->app
== NULL
)
4263 return g_win32_app_supports_uris (info
->app
);
4268 g_win32_app_info_supports_files (GAppInfo
*appinfo
)
4270 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
4272 if (info
->app
== NULL
)
4275 return g_hash_table_size (info
->app
->supported_exts
) > 0;
4280 g_win32_app_info_launch_uris (GAppInfo
*appinfo
,
4282 GAppLaunchContext
*launch_context
,
4285 gboolean res
= FALSE
;
4289 do_files
= g_win32_app_info_supports_files (appinfo
);
4295 obj
= g_new0 (file_or_uri
, 1);
4302 file
= g_file_new_for_uri (uris
->data
);
4303 path
= g_file_get_path (file
);
4305 g_object_unref (file
);
4308 obj
->uri
= g_strdup (uris
->data
);
4310 objs
= g_list_prepend (objs
, obj
);
4314 objs
= g_list_reverse (objs
);
4316 res
= g_win32_app_info_launch_internal (G_WIN32_APP_INFO (appinfo
),
4319 G_SPAWN_SEARCH_PATH
,
4322 g_list_free_full (objs
, free_file_or_uri
);
4328 g_win32_app_info_launch (GAppInfo
*appinfo
,
4330 GAppLaunchContext
*launch_context
,
4333 gboolean res
= FALSE
;
4337 do_uris
= g_win32_app_info_supports_uris (appinfo
);
4343 obj
= g_new0 (file_or_uri
, 1);
4344 obj
->file
= g_file_get_path (G_FILE (files
->data
));
4347 obj
->uri
= g_file_get_uri (G_FILE (files
->data
));
4349 objs
= g_list_prepend (objs
, obj
);
4350 files
= files
->next
;
4353 objs
= g_list_reverse (objs
);
4355 res
= g_win32_app_info_launch_internal (G_WIN32_APP_INFO (appinfo
),
4358 G_SPAWN_SEARCH_PATH
,
4361 g_list_free_full (objs
, free_file_or_uri
);
4366 static const char **
4367 g_win32_app_info_get_supported_types (GAppInfo
*appinfo
)
4369 GWin32AppInfo
*info
= G_WIN32_APP_INFO (appinfo
);
4371 return (const char**) info
->supported_types
;
4375 g_app_info_create_from_commandline (const char *commandline
,
4376 const char *application_name
,
4377 GAppInfoCreateFlags flags
,
4380 GWin32AppInfo
*info
;
4381 GWin32AppInfoApplication
*app
;
4383 g_return_val_if_fail (commandline
, NULL
);
4385 info
= g_object_new (G_TYPE_WIN32_APP_INFO
, NULL
);
4387 app
= g_object_new (G_TYPE_WIN32_APPINFO_APPLICATION
, NULL
);
4389 if (application_name
)
4391 app
->canonical_name
= g_utf8_to_utf16 (application_name
,
4396 app
->canonical_name_u8
= g_strdup (application_name
);
4397 app
->canonical_name_folded
= g_utf8_casefold (application_name
, -1);
4400 app
->command
= g_utf8_to_utf16 (commandline
, -1, NULL
, NULL
, NULL
);
4401 app
->command_u8
= g_strdup (commandline
);
4403 extract_executable (app
->command
,
4405 &app
->executable_basename
,
4406 &app
->executable_folded
,
4409 app
->no_open_with
= FALSE
;
4410 app
->user_specific
= FALSE
;
4411 app
->default_app
= FALSE
;
4414 info
->handler
= NULL
;
4416 return G_APP_INFO (info
);
4419 /* GAppInfo interface init */
4422 g_win32_app_info_iface_init (GAppInfoIface
*iface
)
4424 iface
->dup
= g_win32_app_info_dup
;
4425 iface
->equal
= g_win32_app_info_equal
;
4426 iface
->get_id
= g_win32_app_info_get_id
;
4427 iface
->get_name
= g_win32_app_info_get_name
;
4428 iface
->get_description
= g_win32_app_info_get_description
;
4429 iface
->get_executable
= g_win32_app_info_get_executable
;
4430 iface
->get_icon
= g_win32_app_info_get_icon
;
4431 iface
->launch
= g_win32_app_info_launch
;
4432 iface
->supports_uris
= g_win32_app_info_supports_uris
;
4433 iface
->supports_files
= g_win32_app_info_supports_files
;
4434 iface
->launch_uris
= g_win32_app_info_launch_uris
;
4435 /* iface->should_show = g_win32_app_info_should_show;*/
4436 /* iface->set_as_default_for_type = g_win32_app_info_set_as_default_for_type;*/
4437 /* iface->set_as_default_for_extension = g_win32_app_info_set_as_default_for_extension;*/
4438 /* iface->add_supports_type = g_win32_app_info_add_supports_type;*/
4439 /* iface->can_remove_supports_type = g_win32_app_info_can_remove_supports_type;*/
4440 /* iface->remove_supports_type = g_win32_app_info_remove_supports_type;*/
4441 /* iface->can_delete = g_win32_app_info_can_delete;*/
4442 /* iface->do_delete = g_win32_app_info_delete;*/
4443 iface
->get_commandline
= g_win32_app_info_get_commandline
;
4444 iface
->get_display_name
= g_win32_app_info_get_display_name
;
4445 /* iface->set_as_last_used_for_type = g_win32_app_info_set_as_last_used_for_type;*/
4446 iface
->get_supported_types
= g_win32_app_info_get_supported_types
;
4450 g_app_info_get_default_for_uri_scheme (const char *uri_scheme
)
4452 GWin32AppInfoURLSchema
*scheme
;
4456 scheme_down
= g_utf8_casefold (uri_scheme
, -1);
4461 if (strcmp (scheme_down
, "file") == 0)
4463 g_free (scheme_down
);
4467 g_win32_appinfo_init ();
4468 G_LOCK (gio_win32_appinfo
);
4470 scheme
= g_hash_table_lookup (urls
, scheme_down
);
4471 g_free (scheme_down
);
4474 g_object_ref (scheme
);
4476 G_UNLOCK (gio_win32_appinfo
);
4480 if (scheme
!= NULL
&&
4481 scheme
->chosen_handler
!= NULL
&&
4482 scheme
->chosen_handler
->app
!= NULL
)
4483 result
= g_win32_app_info_new_from_app (scheme
->chosen_handler
->app
,
4484 scheme
->chosen_handler
);
4487 g_object_unref (scheme
);
4493 g_app_info_get_default_for_type (const char *content_type
,
4494 gboolean must_support_uris
)
4496 GWin32AppInfoFileExtension
*ext
;
4498 GWin32AppInfoHandler
*handler
;
4500 GWin32AppInfoApplication
*app
;
4501 GHashTableIter iter
;
4503 ext_down
= g_utf8_casefold (content_type
, -1);
4508 g_win32_appinfo_init ();
4509 G_LOCK (gio_win32_appinfo
);
4511 /* Assuming that "content_type" is a file extension, not a MIME type */
4512 ext
= g_hash_table_lookup (extensions
, ext_down
);
4520 G_UNLOCK (gio_win32_appinfo
);
4524 if (ext
->chosen_handler
!= NULL
&&
4525 ext
->chosen_handler
->app
!= NULL
&&
4526 (!must_support_uris
||
4527 g_win32_app_supports_uris (ext
->chosen_handler
->app
)))
4528 result
= g_win32_app_info_new_from_app (ext
->chosen_handler
->app
,
4529 ext
->chosen_handler
);
4532 g_hash_table_iter_init (&iter
, ext
->handlers
);
4534 while (g_hash_table_iter_next (&iter
, NULL
, (gpointer
*) &handler
))
4537 (!must_support_uris
||
4538 g_win32_app_supports_uris (ext
->chosen_handler
->app
)))
4540 result
= g_win32_app_info_new_from_app (handler
->app
, handler
);
4547 g_hash_table_iter_init (&iter
, ext
->other_apps
);
4548 while (g_hash_table_iter_next (&iter
, NULL
, (gpointer
*) &app
))
4550 if (!must_support_uris
||
4551 g_win32_app_supports_uris (ext
->chosen_handler
->app
))
4553 result
= g_win32_app_info_new_from_app (app
, NULL
);
4559 g_object_unref (ext
);
4566 g_app_info_get_all (void)
4568 GHashTableIter iter
;
4574 g_win32_appinfo_init ();
4575 G_LOCK (gio_win32_appinfo
);
4578 g_hash_table_iter_init (&iter
, apps_by_id
);
4579 while (g_hash_table_iter_next (&iter
, NULL
, &value
))
4580 apps
= g_list_prepend (apps
, g_object_ref (G_OBJECT (value
)));
4582 G_UNLOCK (gio_win32_appinfo
);
4585 for (apps_i
= apps
; apps_i
; apps_i
= apps_i
->next
)
4586 infos
= g_list_prepend (infos
,
4587 g_win32_app_info_new_from_app (apps_i
->data
, NULL
));
4589 g_list_free_full (apps
, g_object_unref
);
4595 g_app_info_get_all_for_type (const char *content_type
)
4597 GWin32AppInfoFileExtension
*ext
;
4599 GWin32AppInfoHandler
*handler
;
4600 GWin32AppInfoApplication
*app
;
4601 GHashTableIter iter
;
4604 ext_down
= g_utf8_casefold (content_type
, -1);
4609 g_win32_appinfo_init ();
4610 G_LOCK (gio_win32_appinfo
);
4612 /* Assuming that "content_type" is a file extension, not a MIME type */
4613 ext
= g_hash_table_lookup (extensions
, ext_down
);
4621 G_UNLOCK (gio_win32_appinfo
);
4626 if (ext
->chosen_handler
!= NULL
&&
4627 ext
->chosen_handler
->app
!= NULL
)
4628 result
= g_list_prepend (result
,
4629 g_win32_app_info_new_from_app (ext
->chosen_handler
->app
,
4630 ext
->chosen_handler
));
4632 g_hash_table_iter_init (&iter
, ext
->handlers
);
4634 while (g_hash_table_iter_next (&iter
, NULL
, (gpointer
*) &handler
))
4637 (ext
->chosen_handler
== NULL
|| ext
->chosen_handler
->app
!= handler
->app
))
4638 result
= g_list_prepend (result
,
4639 g_win32_app_info_new_from_app (handler
->app
,
4643 g_hash_table_iter_init (&iter
, ext
->other_apps
);
4645 while (g_hash_table_iter_next (&iter
, NULL
, (gpointer
*) &app
))
4647 result
= g_list_prepend (result
, g_win32_app_info_new_from_app (app
, NULL
));
4650 g_object_unref (ext
);
4652 result
= g_list_reverse (result
);
4658 g_app_info_get_fallback_for_type (const gchar
*content_type
)
4660 /* TODO: fix this once gcontenttype support is improved */
4661 return g_app_info_get_all_for_type (content_type
);
4665 g_app_info_get_recommended_for_type (const gchar
*content_type
)
4667 /* TODO: fix this once gcontenttype support is improved */
4668 return g_app_info_get_all_for_type (content_type
);
4672 g_app_info_reset_type_associations (const char *content_type
)