Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. | |
3 | * Copyright (C) Colin Harrison 2005-2008 | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining | |
6 | * a copy of this software and associated documentation files (the | |
7 | * "Software"), to deal in the Software without restriction, including | |
8 | * without limitation the rights to use, copy, modify, merge, publish, | |
9 | * distribute, sublicense, and/or sell copies of the Software, and to | |
10 | * permit persons to whom the Software is furnished to do so, subject to | |
11 | * the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be | |
14 | * included in all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR | |
20 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
21 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
23 | * | |
24 | * Except as contained in this notice, the name of the XFree86 Project | |
25 | * shall not be used in advertising or otherwise to promote the sale, use | |
26 | * or other dealings in this Software without prior written authorization | |
27 | * from the XFree86 Project. | |
28 | * | |
29 | * Authors: Earle F. Philhower, III | |
30 | * Colin Harrison | |
31 | */ | |
32 | ||
33 | #ifdef HAVE_XWIN_CONFIG_H | |
34 | #include <xwin-config.h> | |
35 | #endif | |
36 | #include <stdio.h> | |
37 | #include <stdlib.h> | |
38 | #ifdef __CYGWIN__ | |
39 | #include <sys/resource.h> | |
40 | #endif | |
41 | #include "win.h" | |
42 | ||
43 | #include <X11/Xwindows.h> | |
44 | #include <shellapi.h> | |
45 | ||
46 | #include "winprefs.h" | |
47 | #include "winmultiwindowclass.h" | |
48 | ||
49 | /* Where will the custom menu commands start counting from? */ | |
50 | #define STARTMENUID WM_USER | |
51 | ||
52 | extern const char *winGetBaseDir(void); | |
53 | ||
54 | /* From winprefslex.l, the real parser */ | |
55 | extern int parse_file(FILE * fp); | |
56 | ||
57 | /* Currently in use command ID, incremented each new menu item created */ | |
58 | static int g_cmdid = STARTMENUID; | |
59 | ||
60 | /* Local function to handle comma-ified icon names */ | |
61 | static HICON LoadImageComma(char *fname, int sx, int sy, int flags); | |
62 | ||
63 | /* | |
64 | * Creates or appends a menu from a MENUPARSED structure | |
65 | */ | |
66 | static HMENU | |
67 | MakeMenu(char *name, HMENU editMenu, int editItem) | |
68 | { | |
69 | int i; | |
70 | int item; | |
71 | MENUPARSED *m; | |
72 | HMENU hmenu, hsub; | |
73 | ||
74 | for (i = 0; i < pref.menuItems; i++) { | |
75 | if (!strcmp(name, pref.menu[i].menuName)) | |
76 | break; | |
77 | } | |
78 | ||
79 | /* Didn't find a match, bummer */ | |
80 | if (i == pref.menuItems) { | |
81 | ErrorF("MakeMenu: Can't find menu %s\n", name); | |
82 | return NULL; | |
83 | } | |
84 | ||
85 | m = &(pref.menu[i]); | |
86 | ||
87 | if (editMenu) { | |
88 | hmenu = editMenu; | |
89 | item = editItem; | |
90 | } | |
91 | else { | |
92 | hmenu = CreatePopupMenu(); | |
93 | if (!hmenu) { | |
94 | ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name); | |
95 | return NULL; | |
96 | } | |
97 | item = 0; | |
98 | } | |
99 | ||
100 | /* Add the menu items */ | |
101 | for (i = 0; i < m->menuItems; i++) { | |
102 | /* Only assign IDs one time... */ | |
103 | if (m->menuItem[i].commandID == 0) | |
104 | m->menuItem[i].commandID = g_cmdid++; | |
105 | ||
106 | switch (m->menuItem[i].cmd) { | |
107 | case CMD_EXEC: | |
108 | case CMD_ALWAYSONTOP: | |
109 | case CMD_RELOAD: | |
110 | InsertMenu(hmenu, | |
111 | item, | |
112 | MF_BYPOSITION | MF_ENABLED | MF_STRING, | |
113 | m->menuItem[i].commandID, m->menuItem[i].text); | |
114 | break; | |
115 | ||
116 | case CMD_SEPARATOR: | |
117 | InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); | |
118 | break; | |
119 | ||
120 | case CMD_MENU: | |
121 | /* Recursive! */ | |
122 | hsub = MakeMenu(m->menuItem[i].param, 0, 0); | |
123 | if (hsub) | |
124 | InsertMenu(hmenu, | |
125 | item, | |
126 | MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING, | |
127 | (UINT_PTR) hsub, m->menuItem[i].text); | |
128 | break; | |
129 | } | |
130 | ||
131 | /* If item==-1 (means to add at end of menu) don't increment) */ | |
132 | if (item >= 0) | |
133 | item++; | |
134 | } | |
135 | ||
136 | return hmenu; | |
137 | } | |
138 | ||
139 | #ifdef XWIN_MULTIWINDOW | |
140 | /* | |
141 | * Callback routine that is executed once per window class. | |
142 | * Removes or creates custom window settings depending on LPARAM | |
143 | */ | |
144 | static wBOOL CALLBACK | |
145 | ReloadEnumWindowsProc(HWND hwnd, LPARAM lParam) | |
146 | { | |
147 | HICON hicon; | |
148 | ||
149 | if (!hwnd) { | |
150 | ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n"); | |
151 | return FALSE; | |
152 | } | |
153 | ||
154 | /* It's our baby, either clean or dirty it */ | |
155 | if (lParam == FALSE) { | |
156 | /* Reset the window's icon to undefined. */ | |
157 | hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_BIG, 0); | |
158 | ||
159 | /* If the old icon is generated on-the-fly, get rid of it, will regen */ | |
160 | winDestroyIcon(hicon); | |
161 | ||
162 | /* Same for the small icon */ | |
163 | hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0); | |
164 | winDestroyIcon(hicon); | |
165 | ||
166 | /* Remove any menu additions; bRevert=TRUE destroys any modified menus */ | |
167 | GetSystemMenu(hwnd, TRUE); | |
168 | ||
169 | /* This window is now clean of our taint (but with undefined icons) */ | |
170 | } | |
171 | else { | |
172 | /* Send a message to WM thread telling it re-evaluate the icon for this window */ | |
173 | { | |
174 | winWMMessageRec wmMsg; | |
175 | ||
176 | WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP); | |
177 | ||
178 | if (pWin) { | |
179 | winPrivWinPtr pWinPriv = winGetWindowPriv(pWin); | |
180 | winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv; | |
181 | ||
182 | wmMsg.msg = WM_WM_ICON_EVENT; | |
183 | wmMsg.hwndWindow = hwnd; | |
184 | wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP); | |
185 | ||
186 | winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg); | |
187 | } | |
188 | } | |
189 | ||
190 | /* Update the system menu for this window */ | |
191 | SetupSysMenu(hwnd); | |
192 | ||
193 | /* That was easy... */ | |
194 | } | |
195 | ||
196 | return TRUE; | |
197 | } | |
198 | #endif | |
199 | ||
200 | /* | |
201 | * Removes any custom icons in classes, custom menus, etc. | |
202 | * Frees all members in pref structure. | |
203 | * Reloads the preferences file. | |
204 | * Set custom icons and menus again. | |
205 | */ | |
206 | static void | |
207 | ReloadPrefs(void) | |
208 | { | |
209 | int i; | |
210 | ||
211 | #ifdef XWIN_MULTIWINDOW | |
212 | /* First, iterate over all windows, deleting their icons and custom menus. | |
213 | * This is really only needed because winDestroyIcon() will try to | |
214 | * destroy the old global icons, which will have changed. | |
215 | * It is probably better to set a windows USER_DATA to flag locally defined | |
216 | * icons, and use that to accurately know when to destroy old icons. | |
217 | */ | |
218 | EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE); | |
219 | #endif | |
220 | ||
221 | /* Now, free/clear all info from our prefs structure */ | |
222 | for (i = 0; i < pref.menuItems; i++) | |
223 | free(pref.menu[i].menuItem); | |
224 | free(pref.menu); | |
225 | pref.menu = NULL; | |
226 | pref.menuItems = 0; | |
227 | ||
228 | pref.rootMenuName[0] = 0; | |
229 | ||
230 | free(pref.sysMenu); | |
231 | pref.sysMenuItems = 0; | |
232 | ||
233 | pref.defaultSysMenuName[0] = 0; | |
234 | pref.defaultSysMenuPos = 0; | |
235 | ||
236 | pref.iconDirectory[0] = 0; | |
237 | pref.defaultIconName[0] = 0; | |
238 | pref.trayIconName[0] = 0; | |
239 | ||
240 | for (i = 0; i < pref.iconItems; i++) | |
241 | if (pref.icon[i].hicon) | |
242 | DestroyIcon((HICON) pref.icon[i].hicon); | |
243 | free(pref.icon); | |
244 | pref.icon = NULL; | |
245 | pref.iconItems = 0; | |
246 | ||
247 | /* Free global default X icon */ | |
248 | if (g_hIconX) | |
249 | DestroyIcon(g_hIconX); | |
250 | if (g_hSmallIconX) | |
251 | DestroyIcon(g_hSmallIconX); | |
252 | ||
253 | /* Reset the custom command IDs */ | |
254 | g_cmdid = STARTMENUID; | |
255 | ||
256 | /* Load the updated resource file */ | |
257 | LoadPreferences(); | |
258 | ||
259 | g_hIconX = NULL; | |
260 | g_hSmallIconX = NULL; | |
261 | ||
262 | #ifdef XWIN_MULTIWINDOW | |
263 | winInitGlobalIcons(); | |
264 | #endif | |
265 | ||
266 | #ifdef XWIN_MULTIWINDOW | |
267 | /* Rebuild the icons and menus */ | |
268 | EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE); | |
269 | #endif | |
270 | ||
271 | /* Whew, done */ | |
272 | } | |
273 | ||
274 | /* | |
275 | * Check/uncheck the ALWAYSONTOP items in this menu | |
276 | */ | |
277 | void | |
278 | HandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu) | |
279 | { | |
280 | DWORD dwExStyle; | |
281 | int i, j; | |
282 | ||
283 | if (!hwnd || !hmenu) | |
284 | return; | |
285 | ||
286 | if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) | |
287 | dwExStyle = MF_BYCOMMAND | MF_CHECKED; | |
288 | else | |
289 | dwExStyle = MF_BYCOMMAND | MF_UNCHECKED; | |
290 | ||
291 | for (i = 0; i < pref.menuItems; i++) | |
292 | for (j = 0; j < pref.menu[i].menuItems; j++) | |
293 | if (pref.menu[i].menuItem[j].cmd == CMD_ALWAYSONTOP) | |
294 | CheckMenuItem(hmenu, pref.menu[i].menuItem[j].commandID, | |
295 | dwExStyle); | |
296 | ||
297 | } | |
298 | ||
299 | /* | |
300 | * Searches for the custom WM_COMMAND command ID and performs action. | |
301 | * Return TRUE if command is proccessed, FALSE otherwise. | |
302 | */ | |
303 | Bool | |
304 | HandleCustomWM_COMMAND(HWND hwnd, int command) | |
305 | { | |
306 | int i, j; | |
307 | MENUPARSED *m; | |
308 | DWORD dwExStyle; | |
309 | ||
310 | if (!command) | |
311 | return FALSE; | |
312 | ||
313 | for (i = 0; i < pref.menuItems; i++) { | |
314 | m = &(pref.menu[i]); | |
315 | for (j = 0; j < m->menuItems; j++) { | |
316 | if (command == m->menuItem[j].commandID) { | |
317 | /* Match! */ | |
318 | switch (m->menuItem[j].cmd) { | |
319 | #ifdef __CYGWIN__ | |
320 | case CMD_EXEC: | |
321 | if (fork() == 0) { | |
322 | struct rlimit rl; | |
323 | int fd; | |
324 | ||
325 | /* Close any open descriptors except for STD* */ | |
326 | getrlimit(RLIMIT_NOFILE, &rl); | |
327 | for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++) | |
328 | close(fd); | |
329 | ||
330 | /* Disassociate any TTYs */ | |
331 | setsid(); | |
332 | ||
333 | execl("/bin/sh", | |
334 | "/bin/sh", "-c", m->menuItem[j].param, NULL); | |
335 | exit(0); | |
336 | } | |
337 | else | |
338 | return TRUE; | |
339 | break; | |
340 | #else | |
341 | case CMD_EXEC: | |
342 | { | |
343 | /* Start process without console window */ | |
344 | STARTUPINFO start; | |
345 | PROCESS_INFORMATION child; | |
346 | ||
347 | memset(&start, 0, sizeof(start)); | |
348 | start.cb = sizeof(start); | |
349 | start.dwFlags = STARTF_USESHOWWINDOW; | |
350 | start.wShowWindow = SW_HIDE; | |
351 | ||
352 | memset(&child, 0, sizeof(child)); | |
353 | ||
354 | if (CreateProcess | |
355 | (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL, | |
356 | NULL, &start, &child)) { | |
357 | CloseHandle(child.hThread); | |
358 | CloseHandle(child.hProcess); | |
359 | } | |
360 | else | |
361 | MessageBox(NULL, m->menuItem[j].param, | |
362 | "Mingrc Exec Command Error!", | |
363 | MB_OK | MB_ICONEXCLAMATION); | |
364 | } | |
365 | return TRUE; | |
366 | #endif | |
367 | case CMD_ALWAYSONTOP: | |
368 | if (!hwnd) | |
369 | return FALSE; | |
370 | ||
371 | /* Get extended window style */ | |
372 | dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); | |
373 | ||
374 | /* Handle topmost windows */ | |
375 | if (dwExStyle & WS_EX_TOPMOST) | |
376 | SetWindowPos(hwnd, | |
377 | HWND_NOTOPMOST, | |
378 | 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); | |
379 | else | |
380 | SetWindowPos(hwnd, | |
381 | HWND_TOPMOST, | |
382 | 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); | |
383 | #if XWIN_MULTIWINDOW | |
384 | /* Reflect the changed Z order */ | |
385 | winReorderWindowsMultiWindow(); | |
386 | #endif | |
387 | return TRUE; | |
388 | ||
389 | case CMD_RELOAD: | |
390 | ReloadPrefs(); | |
391 | return TRUE; | |
392 | ||
393 | default: | |
394 | return FALSE; | |
395 | } | |
396 | } /* match */ | |
397 | } /* for j */ | |
398 | } /* for i */ | |
399 | ||
400 | return FALSE; | |
401 | } | |
402 | ||
403 | #ifdef XWIN_MULTIWINDOW | |
404 | /* | |
405 | * Add the default or a custom menu depending on the class match | |
406 | */ | |
407 | void | |
408 | SetupSysMenu(HWND hwnd) | |
409 | { | |
410 | HMENU sys; | |
411 | int i; | |
412 | WindowPtr pWin; | |
413 | char *res_name, *res_class; | |
414 | ||
415 | if (!hwnd) | |
416 | return; | |
417 | ||
418 | pWin = GetProp(hwnd, WIN_WINDOW_PROP); | |
419 | ||
420 | sys = GetSystemMenu(hwnd, FALSE); | |
421 | if (!sys) | |
422 | return; | |
423 | ||
424 | if (pWin) { | |
425 | /* First see if there's a class match... */ | |
426 | if (winMultiWindowGetClassHint(pWin, &res_name, &res_class)) { | |
427 | for (i = 0; i < pref.sysMenuItems; i++) { | |
428 | if (!strcmp(pref.sysMenu[i].match, res_name) || | |
429 | !strcmp(pref.sysMenu[i].match, res_class)) { | |
430 | free(res_name); | |
431 | free(res_class); | |
432 | ||
433 | MakeMenu(pref.sysMenu[i].menuName, sys, | |
434 | pref.sysMenu[i].menuPos == AT_START ? 0 : -1); | |
435 | return; | |
436 | } | |
437 | } | |
438 | ||
439 | /* No match, just free alloc'd strings */ | |
440 | free(res_name); | |
441 | free(res_class); | |
442 | } /* Found wm_class */ | |
443 | } /* if pwin */ | |
444 | ||
445 | /* Fallback to system default */ | |
446 | if (pref.defaultSysMenuName[0]) { | |
447 | if (pref.defaultSysMenuPos == AT_START) | |
448 | MakeMenu(pref.defaultSysMenuName, sys, 0); | |
449 | else | |
450 | MakeMenu(pref.defaultSysMenuName, sys, -1); | |
451 | } | |
452 | } | |
453 | #endif | |
454 | ||
455 | /* | |
456 | * Possibly add a menu to the toolbar icon | |
457 | */ | |
458 | void | |
459 | SetupRootMenu(HMENU root) | |
460 | { | |
461 | if (!root) | |
462 | return; | |
463 | ||
464 | if (pref.rootMenuName[0]) { | |
465 | MakeMenu(pref.rootMenuName, root, 0); | |
466 | } | |
467 | } | |
468 | ||
469 | /* | |
470 | * Check for and return an overridden default ICON specified in the prefs | |
471 | */ | |
472 | HICON | |
473 | winOverrideDefaultIcon(int size) | |
474 | { | |
475 | HICON hicon; | |
476 | ||
477 | if (pref.defaultIconName[0]) { | |
478 | hicon = LoadImageComma(pref.defaultIconName, size, size, 0); | |
479 | if (hicon == NULL) | |
480 | ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n", | |
481 | pref.defaultIconName); | |
482 | ||
483 | return hicon; | |
484 | } | |
485 | ||
486 | return 0; | |
487 | } | |
488 | ||
489 | /* | |
490 | * Return the HICON to use in the taskbar notification area | |
491 | */ | |
492 | HICON | |
493 | winTaskbarIcon(void) | |
494 | { | |
495 | HICON hicon; | |
496 | ||
497 | hicon = 0; | |
498 | /* First try and load an overridden, if success then return it */ | |
499 | if (pref.trayIconName[0]) { | |
500 | hicon = LoadImageComma(pref.trayIconName, | |
501 | GetSystemMetrics(SM_CXSMICON), | |
502 | GetSystemMetrics(SM_CYSMICON), 0); | |
503 | } | |
504 | ||
505 | /* Otherwise return the default */ | |
506 | if (!hicon) | |
507 | hicon = (HICON) LoadImage(g_hInstance, | |
508 | MAKEINTRESOURCE(IDI_XWIN), | |
509 | IMAGE_ICON, | |
510 | GetSystemMetrics(SM_CXSMICON), | |
511 | GetSystemMetrics(SM_CYSMICON), 0); | |
512 | ||
513 | return hicon; | |
514 | } | |
515 | ||
516 | /* | |
517 | * Parse a filename to extract an icon: | |
518 | * If fname is exactly ",nnn" then extract icon from our resource | |
519 | * else if it is "file,nnn" then extract icon nnn from that file | |
520 | * else try to load it as an .ico file and if that fails return NULL | |
521 | */ | |
522 | static HICON | |
523 | LoadImageComma(char *fname, int sx, int sy, int flags) | |
524 | { | |
525 | HICON hicon; | |
526 | int i; | |
527 | char file[PATH_MAX + NAME_MAX + 2]; | |
528 | ||
529 | /* Some input error checking */ | |
530 | if (!fname || !fname[0]) | |
531 | return NULL; | |
532 | ||
533 | i = 0; | |
534 | hicon = NULL; | |
535 | ||
536 | if (fname[0] == ',') { | |
537 | /* It's the XWIN.EXE resource they want */ | |
538 | i = atoi(fname + 1); | |
539 | hicon = LoadImage(g_hInstance, | |
540 | MAKEINTRESOURCE(i), IMAGE_ICON, sx, sy, flags); | |
541 | } | |
542 | else { | |
543 | file[0] = 0; | |
544 | /* Prepend path if not given a "X:\" filename */ | |
545 | if (!(fname[0] && fname[1] == ':' && fname[2] == '\\')) { | |
546 | strcpy(file, pref.iconDirectory); | |
547 | if (pref.iconDirectory[0]) | |
548 | if (fname[strlen(fname) - 1] != '\\') | |
549 | strcat(file, "\\"); | |
550 | } | |
551 | strcat(file, fname); | |
552 | ||
553 | if (strrchr(file, ',')) { | |
554 | /* Specified as <fname>,<index> */ | |
555 | ||
556 | *(strrchr(file, ',')) = 0; /* End string at comma */ | |
557 | i = atoi(strrchr(fname, ',') + 1); | |
558 | hicon = ExtractIcon(g_hInstance, file, i); | |
559 | } | |
560 | else { | |
561 | /* Just an .ico file... */ | |
562 | ||
563 | hicon = (HICON) LoadImage(NULL, | |
564 | file, | |
565 | IMAGE_ICON, | |
566 | sx, sy, LR_LOADFROMFILE | flags); | |
567 | } | |
568 | } | |
569 | return hicon; | |
570 | } | |
571 | ||
572 | /* | |
573 | * Check for a match of the window class to one specified in the | |
574 | * ICONS{} section in the prefs file, and load the icon from a file | |
575 | */ | |
576 | HICON | |
577 | winOverrideIcon(char *res_name, char *res_class, char *wmName) | |
578 | { | |
579 | int i; | |
580 | HICON hicon; | |
581 | ||
582 | for (i = 0; i < pref.iconItems; i++) { | |
583 | if ((res_name && !strcmp(pref.icon[i].match, res_name)) || | |
584 | (res_class && !strcmp(pref.icon[i].match, res_class)) || | |
585 | (wmName && strstr(wmName, pref.icon[i].match))) { | |
586 | if (pref.icon[i].hicon) | |
587 | return pref.icon[i].hicon; | |
588 | ||
589 | hicon = LoadImageComma(pref.icon[i].iconFile, 0, 0, LR_DEFAULTSIZE); | |
590 | if (hicon == NULL) | |
591 | ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n", | |
592 | pref.icon[i].iconFile); | |
593 | ||
594 | pref.icon[i].hicon = hicon; | |
595 | return hicon; | |
596 | } | |
597 | } | |
598 | ||
599 | /* Didn't find the icon, fail gracefully */ | |
600 | return 0; | |
601 | } | |
602 | ||
603 | /* | |
604 | * Should we free this icon or leave it in memory (is it part of our | |
605 | * ICONS{} overrides)? | |
606 | */ | |
607 | int | |
608 | winIconIsOverride(HICON hicon) | |
609 | { | |
610 | int i; | |
611 | ||
612 | if (!hicon) | |
613 | return 0; | |
614 | ||
615 | for (i = 0; i < pref.iconItems; i++) | |
616 | if ((HICON) pref.icon[i].hicon == hicon) | |
617 | return 1; | |
618 | ||
619 | return 0; | |
620 | } | |
621 | ||
622 | /* | |
623 | * Open and parse the XWinrc config file @path. | |
624 | * If @path is NULL, use the built-in default. | |
625 | */ | |
626 | static int | |
627 | winPrefsLoadPreferences(char *path) | |
628 | { | |
629 | FILE *prefFile = NULL; | |
630 | ||
631 | if (path) | |
632 | prefFile = fopen(path, "r"); | |
633 | #ifdef __CYGWIN__ | |
634 | else { | |
635 | char defaultPrefs[] = | |
636 | "MENU rmenu {\n" | |
637 | " \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n" | |
638 | " \"Launch xterm\" EXEC xterm\n" | |
639 | " \"Load .XWinrc\" RELOAD\n" | |
640 | " SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n"; | |
641 | ||
642 | path = "built-in default"; | |
643 | prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r"); | |
644 | } | |
645 | #endif | |
646 | ||
647 | if (!prefFile) { | |
648 | ErrorF("LoadPreferences: %s not found\n", path); | |
649 | return FALSE; | |
650 | } | |
651 | ||
652 | ErrorF("LoadPreferences: Loading %s\n", path); | |
653 | ||
654 | if ((parse_file(prefFile)) != 0) { | |
655 | ErrorF("LoadPreferences: %s is badly formed!\n", path); | |
656 | fclose(prefFile); | |
657 | return FALSE; | |
658 | } | |
659 | ||
660 | fclose(prefFile); | |
661 | return TRUE; | |
662 | } | |
663 | ||
664 | /* | |
665 | * Try and open ~/.XWinrc and system.XWinrc | |
666 | * Load it into prefs structure for use by other functions | |
667 | */ | |
668 | void | |
669 | LoadPreferences(void) | |
670 | { | |
671 | char *home; | |
672 | char fname[PATH_MAX + NAME_MAX + 2]; | |
673 | char szDisplay[512]; | |
674 | char *szEnvDisplay; | |
675 | int i, j; | |
676 | char param[PARAM_MAX + 1]; | |
677 | char *srcParam, *dstParam; | |
678 | int parsed = FALSE; | |
679 | ||
680 | /* First, clear all preference settings */ | |
681 | memset(&pref, 0, sizeof(pref)); | |
682 | ||
683 | /* Now try and find a ~/.xwinrc file */ | |
684 | home = getenv("HOME"); | |
685 | if (home) { | |
686 | strcpy(fname, home); | |
687 | if (fname[strlen(fname) - 1] != '/') | |
688 | strcat(fname, "/"); | |
689 | strcat(fname, ".XWinrc"); | |
690 | parsed = winPrefsLoadPreferences(fname); | |
691 | } | |
692 | ||
693 | /* No home file found, check system default */ | |
694 | if (!parsed) { | |
695 | char buffer[MAX_PATH]; | |
696 | ||
697 | #ifdef RELOCATE_PROJECTROOT | |
698 | snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir()); | |
699 | #else | |
700 | strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer)); | |
701 | #endif | |
702 | buffer[sizeof(buffer) - 1] = 0; | |
703 | parsed = winPrefsLoadPreferences(buffer); | |
704 | } | |
705 | ||
706 | /* Neither user nor system configuration found, or were badly formed */ | |
707 | if (!parsed) { | |
708 | ErrorF | |
709 | ("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n"); | |
710 | parsed = winPrefsLoadPreferences(NULL); | |
711 | } | |
712 | ||
713 | /* Setup a DISPLAY environment variable, need to allocate on heap */ | |
714 | /* because putenv doesn't copy the argument... */ | |
715 | snprintf(szDisplay, 512, "DISPLAY=127.0.0.1:%s.0", display); | |
716 | szEnvDisplay = (char *) (malloc(strlen(szDisplay) + 1)); | |
717 | if (szEnvDisplay) { | |
718 | strcpy(szEnvDisplay, szDisplay); | |
719 | putenv(szEnvDisplay); | |
720 | } | |
721 | ||
722 | /* Replace any "%display%" in menu commands with display string */ | |
723 | snprintf(szDisplay, 512, "127.0.0.1:%s.0", display); | |
724 | for (i = 0; i < pref.menuItems; i++) { | |
725 | for (j = 0; j < pref.menu[i].menuItems; j++) { | |
726 | if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) { | |
727 | srcParam = pref.menu[i].menuItem[j].param; | |
728 | dstParam = param; | |
729 | while (*srcParam) { | |
730 | if (!strncmp(srcParam, "%display%", 9)) { | |
731 | memcpy(dstParam, szDisplay, strlen(szDisplay)); | |
732 | dstParam += strlen(szDisplay); | |
733 | srcParam += 9; | |
734 | } | |
735 | else { | |
736 | *dstParam = *srcParam; | |
737 | dstParam++; | |
738 | srcParam++; | |
739 | } | |
740 | } | |
741 | *dstParam = 0; | |
742 | strcpy(pref.menu[i].menuItem[j].param, param); | |
743 | } /* cmd==cmd_exec */ | |
744 | } /* for all menuitems */ | |
745 | } /* for all menus */ | |
746 | ||
747 | } | |
748 | ||
749 | /* | |
750 | * Check for a match of the window class to one specified in the | |
751 | * STYLES{} section in the prefs file, and return the style type | |
752 | */ | |
753 | unsigned long | |
754 | winOverrideStyle(char *res_name, char *res_class, char *wmName) | |
755 | { | |
756 | int i; | |
757 | ||
758 | for (i = 0; i < pref.styleItems; i++) { | |
759 | if ((res_name && !strcmp(pref.style[i].match, res_name)) || | |
760 | (res_class && !strcmp(pref.style[i].match, res_class)) || | |
761 | (wmName && strstr(wmName, pref.style[i].match))) { | |
762 | if (pref.style[i].type) | |
763 | return pref.style[i].type; | |
764 | } | |
765 | } | |
766 | ||
767 | /* Didn't find the style, fail gracefully */ | |
768 | return STYLE_NONE; | |
769 | } |