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