2
* Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3
* Copyright (C) Colin Harrison 2005-2008
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:
13
* The above copyright notice and this permission notice shall be
14
* included in all copies or substantial portions of the Software.
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.
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.
29
* Authors: Earle F. Philhower, III
33
#ifdef HAVE_XWIN_CONFIG_H
34
#include <xwin-config.h>
39
#include <sys/resource.h>
43
#include <X11/Xwindows.h>
47
#include "winmultiwindowclass.h"
49
/* Where will the custom menu commands start counting from? */
50
#define STARTMENUID WM_USER
52
extern const char *winGetBaseDir(void);
54
/* From winprefslex.l, the real parser */
55
extern int parse_file(FILE * fp);
57
/* Currently in use command ID, incremented each new menu item created */
58
static int g_cmdid = STARTMENUID;
60
/* Local function to handle comma-ified icon names */
61
static HICON LoadImageComma(char *fname, int sx, int sy, int flags);
64
* Creates or appends a menu from a MENUPARSED structure
67
MakeMenu(char *name, HMENU editMenu, int editItem)
74
for (i = 0; i < pref.menuItems; i++) {
75
if (!strcmp(name, pref.menu[i].menuName))
79
/* Didn't find a match, bummer */
80
if (i == pref.menuItems) {
81
ErrorF("MakeMenu: Can't find menu %s\n", name);
92
hmenu = CreatePopupMenu();
94
ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name);
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++;
106
switch (m->menuItem[i].cmd) {
108
case CMD_ALWAYSONTOP:
112
MF_BYPOSITION | MF_ENABLED | MF_STRING,
113
m->menuItem[i].commandID, m->menuItem[i].text);
117
InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
122
hsub = MakeMenu(m->menuItem[i].param, 0, 0);
126
MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING,
127
(UINT_PTR) hsub, m->menuItem[i].text);
131
/* If item==-1 (means to add at end of menu) don't increment) */
139
#ifdef XWIN_MULTIWINDOW
141
* Callback routine that is executed once per window class.
142
* Removes or creates custom window settings depending on LPARAM
144
static wBOOL CALLBACK
145
ReloadEnumWindowsProc(HWND hwnd, LPARAM lParam)
150
ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n");
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);
159
/* If the old icon is generated on-the-fly, get rid of it, will regen */
160
winDestroyIcon(hicon);
162
/* Same for the small icon */
163
hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0);
164
winDestroyIcon(hicon);
166
/* Remove any menu additions; bRevert=TRUE destroys any modified menus */
167
GetSystemMenu(hwnd, TRUE);
169
/* This window is now clean of our taint (but with undefined icons) */
172
/* Send a message to WM thread telling it re-evaluate the icon for this window */
174
winWMMessageRec wmMsg;
176
WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP);
179
winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
180
winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv;
182
wmMsg.msg = WM_WM_ICON_EVENT;
183
wmMsg.hwndWindow = hwnd;
184
wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
186
winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
190
/* Update the system menu for this window */
193
/* That was easy... */
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.
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.
218
EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE);
221
/* Now, free/clear all info from our prefs structure */
222
for (i = 0; i < pref.menuItems; i++)
223
free(pref.menu[i].menuItem);
228
pref.rootMenuName[0] = 0;
231
pref.sysMenuItems = 0;
233
pref.defaultSysMenuName[0] = 0;
234
pref.defaultSysMenuPos = 0;
236
pref.iconDirectory[0] = 0;
237
pref.defaultIconName[0] = 0;
238
pref.trayIconName[0] = 0;
240
for (i = 0; i < pref.iconItems; i++)
241
if (pref.icon[i].hicon)
242
DestroyIcon((HICON) pref.icon[i].hicon);
247
/* Free global default X icon */
249
DestroyIcon(g_hIconX);
251
DestroyIcon(g_hSmallIconX);
253
/* Reset the custom command IDs */
254
g_cmdid = STARTMENUID;
256
/* Load the updated resource file */
260
g_hSmallIconX = NULL;
262
#ifdef XWIN_MULTIWINDOW
263
winInitGlobalIcons();
266
#ifdef XWIN_MULTIWINDOW
267
/* Rebuild the icons and menus */
268
EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE);
275
* Check/uncheck the ALWAYSONTOP items in this menu
278
HandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu)
286
if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
287
dwExStyle = MF_BYCOMMAND | MF_CHECKED;
289
dwExStyle = MF_BYCOMMAND | MF_UNCHECKED;
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,
300
* Searches for the custom WM_COMMAND command ID and performs action.
301
* Return TRUE if command is proccessed, FALSE otherwise.
304
HandleCustomWM_COMMAND(HWND hwnd, int command)
313
for (i = 0; i < pref.menuItems; i++) {
315
for (j = 0; j < m->menuItems; j++) {
316
if (command == m->menuItem[j].commandID) {
318
switch (m->menuItem[j].cmd) {
325
/* Close any open descriptors except for STD* */
326
getrlimit(RLIMIT_NOFILE, &rl);
327
for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++)
330
/* Disassociate any TTYs */
334
"/bin/sh", "-c", m->menuItem[j].param, NULL);
343
/* Start process without console window */
345
PROCESS_INFORMATION child;
347
memset(&start, 0, sizeof(start));
348
start.cb = sizeof(start);
349
start.dwFlags = STARTF_USESHOWWINDOW;
350
start.wShowWindow = SW_HIDE;
352
memset(&child, 0, sizeof(child));
355
(NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL,
356
NULL, &start, &child)) {
357
CloseHandle(child.hThread);
358
CloseHandle(child.hProcess);
361
MessageBox(NULL, m->menuItem[j].param,
362
"Mingrc Exec Command Error!",
363
MB_OK | MB_ICONEXCLAMATION);
367
case CMD_ALWAYSONTOP:
371
/* Get extended window style */
372
dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
374
/* Handle topmost windows */
375
if (dwExStyle & WS_EX_TOPMOST)
378
0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
382
0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
384
/* Reflect the changed Z order */
385
winReorderWindowsMultiWindow();
403
#ifdef XWIN_MULTIWINDOW
405
* Add the default or a custom menu depending on the class match
408
SetupSysMenu(HWND hwnd)
413
char *res_name, *res_class;
418
pWin = GetProp(hwnd, WIN_WINDOW_PROP);
420
sys = GetSystemMenu(hwnd, FALSE);
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)) {
433
MakeMenu(pref.sysMenu[i].menuName, sys,
434
pref.sysMenu[i].menuPos == AT_START ? 0 : -1);
439
/* No match, just free alloc'd strings */
442
} /* Found wm_class */
445
/* Fallback to system default */
446
if (pref.defaultSysMenuName[0]) {
447
if (pref.defaultSysMenuPos == AT_START)
448
MakeMenu(pref.defaultSysMenuName, sys, 0);
450
MakeMenu(pref.defaultSysMenuName, sys, -1);
456
* Possibly add a menu to the toolbar icon
459
SetupRootMenu(HMENU root)
464
if (pref.rootMenuName[0]) {
465
MakeMenu(pref.rootMenuName, root, 0);
470
* Check for and return an overridden default ICON specified in the prefs
473
winOverrideDefaultIcon(int size)
477
if (pref.defaultIconName[0]) {
478
hicon = LoadImageComma(pref.defaultIconName, size, size, 0);
480
ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n",
481
pref.defaultIconName);
490
* Return the HICON to use in the taskbar notification area
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);
505
/* Otherwise return the default */
507
hicon = (HICON) LoadImage(g_hInstance,
508
MAKEINTRESOURCE(IDI_XWIN),
510
GetSystemMetrics(SM_CXSMICON),
511
GetSystemMetrics(SM_CYSMICON), 0);
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
523
LoadImageComma(char *fname, int sx, int sy, int flags)
527
char file[PATH_MAX + NAME_MAX + 2];
529
/* Some input error checking */
530
if (!fname || !fname[0])
536
if (fname[0] == ',') {
537
/* It's the XWIN.EXE resource they want */
539
hicon = LoadImage(g_hInstance,
540
MAKEINTRESOURCE(i), IMAGE_ICON, sx, sy, flags);
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] != '\\')
553
if (strrchr(file, ',')) {
554
/* Specified as <fname>,<index> */
556
*(strrchr(file, ',')) = 0; /* End string at comma */
557
i = atoi(strrchr(fname, ',') + 1);
558
hicon = ExtractIcon(g_hInstance, file, i);
561
/* Just an .ico file... */
563
hicon = (HICON) LoadImage(NULL,
566
sx, sy, LR_LOADFROMFILE | flags);
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
577
winOverrideIcon(char *res_name, char *res_class, char *wmName)
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;
589
hicon = LoadImageComma(pref.icon[i].iconFile, 0, 0, LR_DEFAULTSIZE);
591
ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n",
592
pref.icon[i].iconFile);
594
pref.icon[i].hicon = hicon;
599
/* Didn't find the icon, fail gracefully */
604
* Should we free this icon or leave it in memory (is it part of our
605
* ICONS{} overrides)?
608
winIconIsOverride(HICON hicon)
615
for (i = 0; i < pref.iconItems; i++)
616
if ((HICON) pref.icon[i].hicon == hicon)
623
* Open and parse the XWinrc config file @path.
624
* If @path is NULL, use the built-in default.
627
winPrefsLoadPreferences(char *path)
629
FILE *prefFile = NULL;
632
prefFile = fopen(path, "r");
635
char defaultPrefs[] =
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";
642
path = "built-in default";
643
prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r");
648
ErrorF("LoadPreferences: %s not found\n", path);
652
ErrorF("LoadPreferences: Loading %s\n", path);
654
if ((parse_file(prefFile)) != 0) {
655
ErrorF("LoadPreferences: %s is badly formed!\n", path);
665
* Try and open ~/.XWinrc and system.XWinrc
666
* Load it into prefs structure for use by other functions
669
LoadPreferences(void)
672
char fname[PATH_MAX + NAME_MAX + 2];
676
char param[PARAM_MAX + 1];
677
char *srcParam, *dstParam;
680
/* First, clear all preference settings */
681
memset(&pref, 0, sizeof(pref));
683
/* Now try and find a ~/.xwinrc file */
684
home = getenv("HOME");
687
if (fname[strlen(fname) - 1] != '/')
689
strcat(fname, ".XWinrc");
690
parsed = winPrefsLoadPreferences(fname);
693
/* No home file found, check system default */
695
char buffer[MAX_PATH];
697
#ifdef RELOCATE_PROJECTROOT
698
snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir());
700
strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer));
702
buffer[sizeof(buffer) - 1] = 0;
703
parsed = winPrefsLoadPreferences(buffer);
706
/* Neither user nor system configuration found, or were badly formed */
709
("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n");
710
parsed = winPrefsLoadPreferences(NULL);
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));
718
strcpy(szEnvDisplay, szDisplay);
719
putenv(szEnvDisplay);
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;
730
if (!strncmp(srcParam, "%display%", 9)) {
731
memcpy(dstParam, szDisplay, strlen(szDisplay));
732
dstParam += strlen(szDisplay);
736
*dstParam = *srcParam;
742
strcpy(pref.menu[i].menuItem[j].param, param);
743
} /* cmd==cmd_exec */
744
} /* for all menuitems */
745
} /* for all menus */
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
754
winOverrideStyle(char *res_name, char *res_class, char *wmName)
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;
767
/* Didn't find the style, fail gracefully */