Merge branch 'pkahle'
[git-cheetah.git] / explorer / menu.c
blob825bb0f7cdf67af2f75b92c4ce9f5ab0c36cb4d2
1 #include "../common/cache.h"
3 #include <shlobj.h>
4 #include <tchar.h>
5 #include "../common/menuengine.h"
6 #include "../common/cheetahmenu.h"
7 #include "menu.h"
8 #include "ext.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 {
19 HMENU menu;
20 UINT index;
21 UINT first;
22 UINT last;
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,
36 void *platform)
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++;
43 return FALSE;
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,
56 void *platform)
58 struct windows_menu_data *windows_menu = platform;
59 if (windows_menu->last < windows_menu->first + next_active_item)
60 return FALSE;
62 InsertMenu(windows_menu->menu, windows_menu->index,
63 MF_STRING | MF_BYPOSITION,
64 windows_menu->first + next_active_item,
65 item->string);
66 windows_menu->index++;
68 return TRUE;
71 void *start_submenu(struct git_data *this_, const struct menu_item *item,
72 void *platform)
74 struct windows_menu_data *parent_menu = platform;
75 struct windows_menu_data *submenu =
76 malloc(sizeof(struct windows_menu_data));
77 submenu->menu = CreateMenu();
78 InsertMenu(parent_menu->menu, parent_menu->index,
79 MF_POPUP | MF_BYPOSITION, (UINT_PTR)(submenu->menu),
80 item->string);
81 parent_menu->index++;
83 submenu->index = 0;
84 submenu->first = parent_menu->first;
86 return submenu;
89 void end_submenu(void *parent, void *submenu)
91 free(submenu);
94 void check_menu_item(void *platform, int checked)
96 struct windows_menu_data *submenu = platform;
97 /* -1, because it's called __after__ index is increased */
98 CheckMenuItem(submenu->menu, submenu->index - 1,
99 MF_BYPOSITION | (checked ? MF_CHECKED : 0));
103 * These are the functions for handling the context menu.
106 inline STDMETHODIMP query_context_menu(void *p, HMENU menu,
107 UINT index, UINT first_command,
108 UINT last_command, UINT flags)
110 struct git_menu *this_menu = p;
111 struct git_data *this_ = this_menu->git_data;
112 struct windows_menu_data windows_menu =
113 { menu, index, first_command, last_command };
115 if (flags & CMF_DEFAULTONLY)
116 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
118 build_cheetah_menu(this_, &windows_menu);
120 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL,
121 next_active_item);
125 * Perform a couple of transformations, such that a directory
126 * C:\Program Files\Bunch of stuff\in\A dir
127 * becomes
128 * /C/Program\ Files/Bunch\ of\ stuff/in/A\ dir
130 * Assumes path is initially a correctly formed Windows-style path.
131 * Returns a new string.
133 static char *convert_directory_format(const char *path)
135 int i;
136 int size_incr = 0;
137 char *converted;
138 char *dst;
140 /* Figure out how much extra space we need to escape spaces */
141 for (i = 0; i < MAX_PATH && path[i] != '\0'; ++i)
142 if (path[i] == ' ')
143 size_incr++;
145 converted = (char *)calloc(size_incr + i + 1, sizeof(char));
146 dst = converted;
148 /* Transform:
149 * " " -> "\ "
150 * "\" -> "/"
152 for (i = 0; i < MAX_PATH && path[i] != '\0'; ++i)
154 switch (path[i])
156 case ' ':
157 *(dst++) = '\\';
158 *(dst++) = ' ';
159 break;
160 case '\\':
161 *(dst++) = '/';
162 break;
163 default:
164 *(dst++) = path[i];
165 break;
168 *dst = '\0';
170 /* X: -> /X */
171 converted[1] = converted[0];
172 converted[0] = '/';
174 return converted;
177 static void free_platform_argv(void *data)
179 free(data);
182 const char **menu_get_platform_argv(menu_commands cmd, const void *data,
183 free_func_t *free_argv, void **argv_data)
185 int n;
186 const char *wd = data;
187 const char **argv;
188 const char *history_argv[] = { "sh", "--login", "-i",
189 "/bin/gitk", "HEAD", "--", NULL, NULL };
190 /* start is required because exec_program does not create a window */
191 const char *bash_argv[] = { "start", "sh", "--login",
192 "-i", NULL };
194 *free_argv = NULL;
195 *argv_data = NULL;
197 switch(cmd)
199 case MENU_HISTORY:
200 history_argv[6] = wd;
202 argv = xmalloc(sizeof(history_argv));
203 memcpy(argv, history_argv, sizeof(history_argv));
205 break;
207 case MENU_BASH:
209 argv = xmalloc(sizeof(bash_argv));
210 memcpy(argv, bash_argv, sizeof(bash_argv));
212 break;
214 default:
215 return NULL;
218 *free_argv = free_platform_argv;
219 *argv_data = argv;
221 return argv;
224 inline STDMETHODIMP invoke_command(void *p,
225 LPCMINVOKECOMMANDINFO info)
227 struct git_menu *this_menu = p;
228 struct git_data *this_ = this_menu->git_data;
229 UINT id = LOWORD(info->lpVerb);
231 if (HIWORD(info->lpVerb))
232 return E_INVALIDARG;
234 handle_menu_item(this_, id);
235 return S_OK;
238 inline STDMETHODIMP get_command_string(void *p, UINT id,
239 UINT flags, UINT *reserved,
240 LPSTR name, UINT size)
242 const char *text;
244 if (!(flags & GCS_HELPTEXT))
245 return E_INVALIDARG;
247 text = get_menu_item_text(id);
248 if (!text)
249 return E_INVALIDARG;
251 if (flags & GCS_UNICODE) {
252 size_t len = strlen(text) + 1;
253 LPWSTR tw = malloc(len * sizeof(wchar_t));
254 /* need to convert terminating NULL as well */
255 mbstowcs(tw, text, len);
256 lstrcpynW((LPWSTR)name, tw, size);
257 free(tw);
258 } else
259 lstrcpynA(name, text, size);
261 return S_OK;
264 DEFINE_STANDARD_METHODS(git_menu)
266 struct git_menu_virtual_table git_menu_virtual_table = {
267 query_interface_git_menu,
268 add_ref_git_menu,
269 release_git_menu,
270 query_context_menu,
271 invoke_command,
272 get_command_string