1 #include "../common/cache.h"
5 #include "../common/menuengine.h"
6 #include "../common/cheetahmenu.h"
9 #include "../common/debug.h"
10 #include "../common/systeminfo.h"
11 #include "../common/exec.h"
13 #define LONGEST_MENU_ITEM 40
16 * Windows-specific Cheetah menu functions
18 struct windows_menu_data
{
25 void reset_platform(void *platform
)
27 /* On Windows, we don't do anything to reset the menu */
31 * menu_item_builder to build a Windows-specific menu separator
33 * Always returns FALSE so the menu engine does not track this item
35 BOOL
build_separator(struct git_data
*data
, const struct menu_item
*item
,
38 struct windows_menu_data
*windows_menu
= platform
;
39 InsertMenu(windows_menu
->menu
, windows_menu
->index
,
40 MF_SEPARATOR
| MF_BYPOSITION
, 0, "");
41 windows_menu
->index
++;
47 * menu_item_builder to build a simple menu item
49 * Explorer's context menu are limited in the number of comands
50 * that they can use, so build_item would:
51 * - do nothing if that limit is reached and return FALSE to
52 * instruct the menu engine to not track this item
53 * - create item and return TRUE, so the item can be handled later
55 BOOL
build_item(struct git_data
*data
, const struct menu_item
*item
,
60 struct windows_menu_data
*windows_menu
= platform
;
61 if (windows_menu
->last
< windows_menu
->first
+ next_active_item
)
64 memset(&mii
, 0, sizeof(MENUITEMINFO
));
65 mii
.cbSize
= sizeof(MENUITEMINFO
);
66 mii
.fMask
= MIIM_STRING
| MIIM_ID
| MIIM_DATA
;
67 mii
.wID
= windows_menu
->first
+ next_active_item
;
68 mii
.dwItemData
= (ULONG_PTR
) hInst
;
69 mii
.dwTypeData
= item
->string
;
70 InsertMenuItem(windows_menu
->menu
, windows_menu
->index
, TRUE
, &mii
);
72 if (item
->flags
& MI_CHECKED
)
73 CheckMenuItem(windows_menu
->menu
, windows_menu
->index
,
74 MF_BYPOSITION
| MF_CHECKED
);
76 windows_menu
->index
++;
80 void *start_submenu(struct git_data
*this_
, const struct menu_item
*item
,
83 struct windows_menu_data
*parent_menu
= platform
;
84 struct windows_menu_data
*submenu
=
85 xmalloc(sizeof(struct windows_menu_data
));
88 submenu
->menu
= CreateMenu();
90 memset(&mii
, 0, sizeof(MENUITEMINFO
));
91 mii
.cbSize
= sizeof(MENUITEMINFO
);
92 mii
.fMask
= MIIM_STRING
| MIIM_DATA
| MIIM_SUBMENU
;
93 mii
.dwItemData
= (ULONG_PTR
) hInst
;
94 mii
.dwTypeData
= item
->string
;
95 mii
.hSubMenu
= submenu
->menu
;
96 InsertMenuItem(parent_menu
->menu
, parent_menu
->index
, TRUE
, &mii
);
101 submenu
->first
= parent_menu
->first
;
102 submenu
->last
= parent_menu
->last
;
107 void end_submenu(void *parent
, void *submenu
)
112 BOOL
menu_exists(HMENU menu
)
116 memset(&mii
, 0, sizeof(MENUITEMINFO
));
117 mii
.cbSize
= sizeof(MENUITEMINFO
);
118 mii
.fMask
= MIIM_DATA
;
119 mii
.dwTypeData
= NULL
;
121 count
= GetMenuItemCount(menu
);
122 for (i
= 0; i
< count
; ++i
)
124 GetMenuItemInfo(menu
, i
, TRUE
, &mii
);
125 if (mii
.dwItemData
== (ULONG_PTR
) hInst
)
135 * These are the functions for handling the context menu.
138 STDMETHODIMP
query_context_menu(void *p
, HMENU menu
,
139 UINT index
, UINT first_command
,
140 UINT last_command
, UINT flags
)
142 struct git_menu
*this_menu
= p
;
143 struct git_data
*this_
= this_menu
->git_data
;
144 struct windows_menu_data windows_menu
=
145 { menu
, index
, first_command
, last_command
};
147 if (flags
& CMF_DEFAULTONLY
)
148 return MAKE_HRESULT(SEVERITY_SUCCESS
, FACILITY_NULL
, 0);
150 if (menu_exists(menu
))
151 return MAKE_HRESULT(SEVERITY_SUCCESS
, FACILITY_NULL
, 0);
153 build_cheetah_menu(this_
, &windows_menu
);
155 return MAKE_HRESULT(SEVERITY_SUCCESS
, FACILITY_NULL
,
160 * Perform a couple of transformations, such that a directory
161 * C:\Program Files\Bunch of stuff\in\A dir
163 * /C/Program\ Files/Bunch\ of\ stuff/in/A\ dir
165 * Assumes path is initially a correctly formed Windows-style path.
166 * Returns a new string.
168 static char *convert_directory_format(const char *path
)
170 /* assuming that each character has to be escaped,
171 allocate twice as much memory */
172 char *converted
= (char *)calloc(2 * strlen(path
) + 1, sizeof(char));
173 char *dst
= converted
;
177 * chars, special to bash, are escaped with "\"
179 for (; *path
; path
++)
205 converted
[1] = converted
[0];
211 static void free_platform_argv(void *data
)
217 #define SYSTEMDIR "system32"
219 #define SYSTEMDIR "syswow64"
222 static const char *get_cmd(void)
224 static struct strbuf buf
= STRBUF_INIT
;
227 strbuf_addf(&buf
, "%s\\" SYSTEMDIR
"\\cmd.exe",
233 static void *create_bash_argv(char *wd
)
235 /* start is required because exec_program does not create a window */
236 static const char *bash_argv
[] = { NULL
, "/c", "start",
237 "sh", "-c", NULL
, NULL
};
238 static const char *command
= "cd %s && sh -l -i";
239 void *argv
= xmalloc(sizeof(bash_argv
));
240 struct strbuf shell_cmd
= STRBUF_INIT
;
241 char *converted
= convert_directory_format(wd
);
243 /* strbuf_addf allocates only 64 bytes, so we have to grow it manually */
244 strbuf_grow(&shell_cmd
, strlen(converted
) + strlen(command
) + 1);
245 strbuf_addf(&shell_cmd
, command
, converted
);
248 bash_argv
[0] = get_cmd();
249 bash_argv
[5] = shell_cmd
.buf
;
251 memcpy(argv
, bash_argv
, sizeof(bash_argv
));
253 /* start the cmd on a system drive, so it does not fail on UNC */
254 strcpy(wd
, getenv("SYSTEMDRIVE"));
259 static void free_bash_argv(void *data
)
261 void **argv
= (void **)data
;
266 const char **menu_get_platform_argv(menu_commands cmd
, void *data
,
267 free_func_t
*free_argv
, void **argv_data
)
271 const char *history_argv
[] = { "sh", "--login", "-i",
272 "/bin/gitk", "HEAD", "--", NULL
, NULL
};
279 history_argv
[6] = wd
;
281 argv
= xmalloc(sizeof(history_argv
));
282 memcpy(argv
, history_argv
, sizeof(history_argv
));
283 *free_argv
= free_platform_argv
;
289 argv
= create_bash_argv(wd
);
290 *free_argv
= free_bash_argv
;
303 STDMETHODIMP
invoke_command(void *p
,
304 LPCMINVOKECOMMANDINFO info
)
306 struct git_menu
*this_menu
= p
;
307 struct git_data
*this_
= this_menu
->git_data
;
308 UINT id
= LOWORD(info
->lpVerb
);
310 if (HIWORD(info
->lpVerb
))
313 handle_menu_item(this_
, id
);
317 STDMETHODIMP
get_command_string(void *p
, UINT id
,
318 UINT flags
, UINT
*reserved
,
319 LPSTR name
, UINT size
)
323 if (!(flags
& GCS_HELPTEXT
))
326 text
= get_menu_item_text(id
);
330 if (flags
& GCS_UNICODE
) {
331 size_t len
= strlen(text
) + 1;
332 LPWSTR tw
= xmalloc(len
* sizeof(wchar_t));
333 /* need to convert terminating NULL as well */
334 mbstowcs(tw
, text
, len
);
335 lstrcpynW((LPWSTR
)name
, tw
, size
);
338 lstrcpynA(name
, text
, size
);
343 DEFINE_STANDARD_METHODS(git_menu
)
345 struct git_menu_virtual_table git_menu_virtual_table
= {
346 query_interface_git_menu
,