xserver-multidpi/hw/xwin/winprefs.c

806 lines
23 KiB
C
Raw Normal View History

2003-11-25 20:29:01 +01:00
/*
* Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
* Copyright (C) Colin Harrison 2005-2008
2003-11-25 20:29:01 +01:00
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the XFree86 Project
* shall not be used in advertising or otherwise to promote the sale, use
* or other dealings in this Software without prior written authorization
* from the XFree86 Project.
*
* Authors: Earle F. Philhower, III
* Colin Harrison
2003-11-25 20:29:01 +01:00
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
2003-11-25 20:29:01 +01:00
#include <stdio.h>
#include <stdlib.h>
#ifdef __CYGWIN__
2003-11-25 20:29:01 +01:00
#include <sys/resource.h>
#include <sys/cygwin.h>
#endif
2003-11-25 20:29:01 +01:00
#include "win.h"
#include <X11/Xwindows.h>
2004-06-21 15:19:32 +02:00
#include <shellapi.h>
2003-11-25 20:29:01 +01:00
#include "winprefs.h"
#include "windisplay.h"
2003-11-25 20:29:01 +01:00
#include "winmultiwindowclass.h"
#include "winmultiwindowicons.h"
2003-11-25 20:29:01 +01:00
/* Where will the custom menu commands start counting from? */
#define STARTMENUID WM_USER
extern const char *winGetBaseDir(void);
/* From winprefslex.l, the real parser */
extern int parse_file(FILE * fp);
2003-11-25 20:29:01 +01:00
/* Currently in use command ID, incremented each new menu item created */
static int g_cmdid = STARTMENUID;
/*
* Creates or appends a menu from a MENUPARSED structure
*/
static HMENU
MakeMenu(char *name, HMENU editMenu, int editItem)
2003-11-25 20:29:01 +01:00
{
int i;
int item;
MENUPARSED *m;
HMENU hmenu, hsub;
for (i = 0; i < pref.menuItems; i++) {
if (!strcmp(name, pref.menu[i].menuName))
break;
2003-11-25 20:29:01 +01:00
}
/* Didn't find a match, bummer */
if (i == pref.menuItems) {
ErrorF("MakeMenu: Can't find menu %s\n", name);
return NULL;
2003-11-25 20:29:01 +01:00
}
m = &(pref.menu[i]);
if (editMenu) {
hmenu = editMenu;
item = editItem;
2003-11-25 20:29:01 +01:00
}
else {
hmenu = CreatePopupMenu();
if (!hmenu) {
ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name);
return NULL;
}
item = 0;
2003-11-25 20:29:01 +01:00
}
/* Add the menu items */
for (i = 0; i < m->menuItems; i++) {
/* Only assign IDs one time... */
if (m->menuItem[i].commandID == 0)
m->menuItem[i].commandID = g_cmdid++;
switch (m->menuItem[i].cmd) {
case CMD_EXEC:
case CMD_ALWAYSONTOP:
case CMD_RELOAD:
InsertMenu(hmenu,
item,
MF_BYPOSITION | MF_ENABLED | MF_STRING,
m->menuItem[i].commandID, m->menuItem[i].text);
break;
case CMD_SEPARATOR:
InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
break;
case CMD_MENU:
/* Recursive! */
hsub = MakeMenu(m->menuItem[i].param, 0, 0);
if (hsub)
InsertMenu(hmenu,
item,
MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING,
(UINT_PTR) hsub, m->menuItem[i].text);
break;
}
/* If item==-1 (means to add at end of menu) don't increment) */
if (item >= 0)
item++;
2003-11-25 20:29:01 +01:00
}
return hmenu;
2003-11-25 20:29:01 +01:00
}
/*
* Callback routine that is executed once per window class.
* Removes or creates custom window settings depending on LPARAM
*/
static wBOOL CALLBACK
ReloadEnumWindowsProc(HWND hwnd, LPARAM lParam)
2003-11-25 20:29:01 +01:00
{
HICON hicon;
2003-11-25 20:29:01 +01:00
if (!hwnd) {
ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n");
return FALSE;
}
2003-11-25 20:29:01 +01:00
/* It's our baby, either clean or dirty it */
if (lParam == FALSE) {
/* Reset the window's icon to undefined. */
hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_BIG, 0);
2003-11-25 20:29:01 +01:00
/* If the old icon is generated on-the-fly, get rid of it, will regen */
winDestroyIcon(hicon);
2004-06-21 15:19:32 +02:00
/* Same for the small icon */
hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0);
winDestroyIcon(hicon);
/* Remove any menu additions; bRevert=TRUE destroys any modified menus */
GetSystemMenu(hwnd, TRUE);
/* This window is now clean of our taint (but with undefined icons) */
2003-11-25 20:29:01 +01:00
}
else {
hw/xwin: Make winOverrideIcon() thread-safe for icon data access winOverrideIcon() is called from the internal WM client thread. Accessing server-internal data structures to get icon data or window hints is not safe, as there is no lock to ensure we do not collide with these data structures being updated in the server thread. Rewrite so the internal client thread uses X client calls to obtain this data safely We used to also set the icon inside the server when the window was initially created. For simplicity, we simply send a message to the internal WM to update the icon when the window is created (rather than writing different icon update code which can work in the server thread for that one case...) extwm mode used to do the icon update in the server. I'm not sure that actually made much sense. Let's assume the external WM client can do it instead... v2 Make sure that WM_WM_ICON_EVENT does nothing for override-redirect windows v3 Reinstate check that native window actually has expected properties for an X window before trying to update it's icon; some auxiliary windows owned by the XWin process don't, which would cause a crash v4 Various fixes to pixmap icon conversion: - remove left-over malloc in winScaleXimageToWindowsIcon causing a memory leak - don't recalculate DDBitmap stride in winScaleXimageToWindowsIcon, when we already have worked it out - properly check that XGetWindowProperty(NET_WM_ICON) returned some data - don't try to retrieve WM_HINTS icon_mask if it isn't set - restore accidentally dropped calculation of effBpp, stride, maskStride of output DDBitmap - make sure imageMask is zero-initalized before we use it to mask the DDBitmap v5 Remove a left-over unused variable v6 Avoid XDestroyImage(NULL) crash if XGetImage failed for icon_pixmap Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk> Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
2012-07-21 15:09:16 +02:00
/* Send a message to WM thread telling it re-evaluate the icon for this window */
{
winWMMessageRec wmMsg;
WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP);
if (pWin) {
winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv;
wmMsg.msg = WM_WM_ICON_EVENT;
wmMsg.hwndWindow = hwnd;
wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
hw/xwin: Make winOverrideIcon() thread-safe for icon data access winOverrideIcon() is called from the internal WM client thread. Accessing server-internal data structures to get icon data or window hints is not safe, as there is no lock to ensure we do not collide with these data structures being updated in the server thread. Rewrite so the internal client thread uses X client calls to obtain this data safely We used to also set the icon inside the server when the window was initially created. For simplicity, we simply send a message to the internal WM to update the icon when the window is created (rather than writing different icon update code which can work in the server thread for that one case...) extwm mode used to do the icon update in the server. I'm not sure that actually made much sense. Let's assume the external WM client can do it instead... v2 Make sure that WM_WM_ICON_EVENT does nothing for override-redirect windows v3 Reinstate check that native window actually has expected properties for an X window before trying to update it's icon; some auxiliary windows owned by the XWin process don't, which would cause a crash v4 Various fixes to pixmap icon conversion: - remove left-over malloc in winScaleXimageToWindowsIcon causing a memory leak - don't recalculate DDBitmap stride in winScaleXimageToWindowsIcon, when we already have worked it out - properly check that XGetWindowProperty(NET_WM_ICON) returned some data - don't try to retrieve WM_HINTS icon_mask if it isn't set - restore accidentally dropped calculation of effBpp, stride, maskStride of output DDBitmap - make sure imageMask is zero-initalized before we use it to mask the DDBitmap v5 Remove a left-over unused variable v6 Avoid XDestroyImage(NULL) crash if XGetImage failed for icon_pixmap Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk> Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
2012-07-21 15:09:16 +02:00
winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
}
}
/* Update the system menu for this window */
SetupSysMenu(hwnd);
2003-11-25 20:29:01 +01:00
/* That was easy... */
2003-11-25 20:29:01 +01:00
}
return TRUE;
2003-11-25 20:29:01 +01:00
}
/*
* Removes any custom icons in classes, custom menus, etc.
* Frees all members in pref structure.
* Reloads the preferences file.
* Set custom icons and menus again.
*/
static void
ReloadPrefs(winPrivScreenPtr pScreenPriv)
2003-11-25 20:29:01 +01:00
{
int i;
2003-11-25 20:29:01 +01:00
winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
/* First, iterate over all windows, deleting their icons and custom menus.
* This is really only needed because winDestroyIcon() will try to
* destroy the old global icons, which will have changed.
* It is probably better to set a windows USER_DATA to flag locally defined
* icons, and use that to accurately know when to destroy old icons.
*/
if (pScreenInfo->fMultiWindow)
EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE);
/* Now, free/clear all info from our prefs structure */
for (i = 0; i < pref.menuItems; i++)
free(pref.menu[i].menuItem);
free(pref.menu);
pref.menu = NULL;
pref.menuItems = 0;
pref.rootMenuName[0] = 0;
free(pref.sysMenu);
pref.sysMenuItems = 0;
pref.defaultSysMenuName[0] = 0;
pref.defaultSysMenuPos = 0;
pref.iconDirectory[0] = 0;
pref.defaultIconName[0] = 0;
pref.trayIconName[0] = 0;
for (i = 0; i < pref.iconItems; i++)
if (pref.icon[i].hicon)
DestroyIcon((HICON) pref.icon[i].hicon);
free(pref.icon);
pref.icon = NULL;
pref.iconItems = 0;
/* Free global default X icon */
if (g_hIconX)
DestroyIcon(g_hIconX);
if (g_hSmallIconX)
DestroyIcon(g_hSmallIconX);
/* Reset the custom command IDs */
g_cmdid = STARTMENUID;
/* Load the updated resource file */
LoadPreferences();
g_hIconX = NULL;
g_hSmallIconX = NULL;
2004-06-21 15:19:32 +02:00
if (pScreenInfo->fMultiWindow) {
winInitGlobalIcons();
/* Rebuild the icons and menus */
EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE);
}
2003-11-25 20:29:01 +01:00
/* Whew, done */
2003-11-25 20:29:01 +01:00
}
/*
* Check/uncheck the ALWAYSONTOP items in this menu
*/
void
HandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu)
2003-11-25 20:29:01 +01:00
{
DWORD dwExStyle;
int i, j;
if (!hwnd || !hmenu)
return;
if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
dwExStyle = MF_BYCOMMAND | MF_CHECKED;
else
dwExStyle = MF_BYCOMMAND | MF_UNCHECKED;
for (i = 0; i < pref.menuItems; i++)
for (j = 0; j < pref.menu[i].menuItems; j++)
if (pref.menu[i].menuItem[j].cmd == CMD_ALWAYSONTOP)
CheckMenuItem(hmenu, pref.menu[i].menuItem[j].commandID,
dwExStyle);
2003-11-25 20:29:01 +01:00
}
2003-11-25 20:29:01 +01:00
/*
2004-06-21 15:19:32 +02:00
* Searches for the custom WM_COMMAND command ID and performs action.
* Return TRUE if command is processed, FALSE otherwise.
2003-11-25 20:29:01 +01:00
*/
2004-06-21 15:19:32 +02:00
Bool
HandleCustomWM_COMMAND(HWND hwnd, WORD command, winPrivScreenPtr pScreenPriv)
2003-11-25 20:29:01 +01:00
{
int i, j;
MENUPARSED *m;
DWORD dwExStyle;
if (!command)
return FALSE;
for (i = 0; i < pref.menuItems; i++) {
m = &(pref.menu[i]);
for (j = 0; j < m->menuItems; j++) {
if (command == m->menuItem[j].commandID) {
/* Match! */
switch (m->menuItem[j].cmd) {
#ifdef __CYGWIN__
case CMD_EXEC:
if (fork() == 0) {
struct rlimit rl;
int fd;
/* Close any open descriptors except for STD* */
getrlimit(RLIMIT_NOFILE, &rl);
for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++)
close(fd);
/* Disassociate any TTYs */
setsid();
execl("/bin/sh",
"/bin/sh", "-c", m->menuItem[j].param, NULL);
exit(0);
}
else
return TRUE;
break;
#else
case CMD_EXEC:
{
/* Start process without console window */
STARTUPINFO start;
PROCESS_INFORMATION child;
memset(&start, 0, sizeof(start));
start.cb = sizeof(start);
start.dwFlags = STARTF_USESHOWWINDOW;
start.wShowWindow = SW_HIDE;
memset(&child, 0, sizeof(child));
if (CreateProcess
(NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL,
NULL, &start, &child)) {
CloseHandle(child.hThread);
CloseHandle(child.hProcess);
}
else
MessageBox(NULL, m->menuItem[j].param,
"Mingrc Exec Command Error!",
MB_OK | MB_ICONEXCLAMATION);
}
return TRUE;
#endif
case CMD_ALWAYSONTOP:
if (!hwnd)
return FALSE;
/* Get extended window style */
dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
/* Handle topmost windows */
if (dwExStyle & WS_EX_TOPMOST)
SetWindowPos(hwnd,
HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
else
SetWindowPos(hwnd,
HWND_TOPMOST,
0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
{
winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
if (pScreenInfo->fMultiWindow)
/* Reflect the changed Z order */
winReorderWindowsMultiWindow();
}
return TRUE;
2003-11-25 20:29:01 +01:00
case CMD_RELOAD:
ReloadPrefs(pScreenPriv);
return TRUE;
default:
return FALSE;
}
} /* match */
} /* for j */
} /* for i */
return FALSE;
}
2003-11-25 20:29:01 +01:00
/*
* Add the default or a custom menu depending on the class match
*/
void
SetupSysMenu(HWND hwnd)
2003-11-25 20:29:01 +01:00
{
HMENU sys;
int i;
WindowPtr pWin;
char *res_name, *res_class;
if (!hwnd)
return;
pWin = GetProp(hwnd, WIN_WINDOW_PROP);
sys = GetSystemMenu(hwnd, FALSE);
if (!sys)
return;
if (pWin) {
/* First see if there's a class match... */
if (winMultiWindowGetClassHint(pWin, &res_name, &res_class)) {
for (i = 0; i < pref.sysMenuItems; i++) {
if (!strcmp(pref.sysMenu[i].match, res_name) ||
!strcmp(pref.sysMenu[i].match, res_class)) {
free(res_name);
free(res_class);
MakeMenu(pref.sysMenu[i].menuName, sys,
pref.sysMenu[i].menuPos == AT_START ? 0 : -1);
return;
}
}
/* No match, just free alloc'd strings */
free(res_name);
free(res_class);
} /* Found wm_class */
} /* if pwin */
/* Fallback to system default */
if (pref.defaultSysMenuName[0]) {
if (pref.defaultSysMenuPos == AT_START)
MakeMenu(pref.defaultSysMenuName, sys, 0);
else
MakeMenu(pref.defaultSysMenuName, sys, -1);
2003-11-25 20:29:01 +01:00
}
}
/*
* Possibly add a menu to the toolbar icon
*/
void
SetupRootMenu(HMENU root)
2003-11-25 20:29:01 +01:00
{
if (!root)
return;
2003-11-25 20:29:01 +01:00
if (pref.rootMenuName[0]) {
MakeMenu(pref.rootMenuName, root, 0);
2003-11-25 20:29:01 +01:00
}
}
/*
* Check for and return an overridden default ICON specified in the prefs
*/
HICON
2004-06-21 15:19:32 +02:00
winOverrideDefaultIcon(int size)
2003-11-25 20:29:01 +01:00
{
HICON hicon;
if (pref.defaultIconName[0]) {
hicon = LoadImageComma(pref.defaultIconName, pref.iconDirectory, size, size, 0);
if (hicon == NULL)
ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n",
pref.defaultIconName);
return hicon;
2003-11-25 20:29:01 +01:00
}
return 0;
2003-11-25 20:29:01 +01:00
}
2004-06-21 15:19:32 +02:00
/*
* Return the HICON to use in the taskbar notification area
*/
HICON
2004-06-21 15:19:32 +02:00
winTaskbarIcon(void)
{
HICON hicon;
hicon = 0;
/* First try and load an overridden, if success then return it */
if (pref.trayIconName[0]) {
hicon = LoadImageComma(pref.trayIconName, pref.iconDirectory,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), 0);
if (hicon == NULL)
ErrorF("winTaskbarIcon: LoadImageComma(%s) failed\n",
pref.trayIconName);
2004-06-21 15:19:32 +02:00
}
/* Otherwise return the default */
if (!hicon)
hicon = (HICON) LoadImage(g_hInstance,
MAKEINTRESOURCE(IDI_XWIN),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), 0);
2004-06-21 15:19:32 +02:00
return hicon;
2004-06-21 15:19:32 +02:00
}
/*
* Handle comma-ified icon names
*
2004-06-21 15:19:32 +02:00
* Parse a filename to extract an icon:
* If fname is exactly ",nnn" then extract icon from our resource
* else if it is "file,nnn" then extract icon nnn from that file
* else try to load it as an .ico file and if that fails return NULL
*/
HICON
LoadImageComma(char *fname, char *iconDirectory, int sx, int sy, int flags)
2004-06-21 15:19:32 +02:00
{
HICON hicon;
int i;
/* Some input error checking */
if (!fname || !fname[0])
return NULL;
i = 0;
hicon = NULL;
if (fname[0] == ',') {
/* It's the XWIN.EXE resource they want */
i = atoi(fname + 1);
hicon = LoadImage(g_hInstance,
MAKEINTRESOURCE(i), IMAGE_ICON, sx, sy, flags);
2004-06-21 15:19:32 +02:00
}
else {
char *file = malloc(PATH_MAX + NAME_MAX + 2);
Bool convert = FALSE;
if (!file)
return NULL;
file[0] = 0;
/* If fname starts 'X:\', it's an absolute Windows path, do nothing */
if (!(fname[0] && fname[1] == ':' && fname[2] == '\\')) {
#ifdef __CYGWIN__
/* If fname starts with '/', it's an absolute cygwin path, we'll
need to convert it */
if (fname[0] == '/') {
convert = TRUE;
}
else
#endif
if (iconDirectory) {
/* Otherwise, prepend the default icon directory, which
currently must be in absolute Windows path form */
strcpy(file, iconDirectory);
if (iconDirectory[0])
if (iconDirectory[strlen(iconDirectory) - 1] != '\\')
strcat(file, "\\");
}
}
strcat(file, fname);
/* Trim off any ',index' */
if (strrchr(file, ',')) {
*(strrchr(file, ',')) = 0; /* End string at comma */
i = atoi(strrchr(fname, ',') + 1);
}
else {
i = -1;
}
#ifdef __CYGWIN__
/* Convert from Cygwin path to Windows path */
if (convert) {
char *converted_file = cygwin_create_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file);
if (converted_file) {
free(file);
file = converted_file;
}
}
#endif
if (i >= 0) {
/* Specified as <fname>,<index> */
hicon = ExtractIcon(g_hInstance, file, i);
}
else {
/* Specified as just an .ico file */
hicon = (HICON) LoadImage(NULL,
file,
IMAGE_ICON,
sx, sy, LR_LOADFROMFILE | flags);
2004-06-21 15:19:32 +02:00
}
free(file);
2004-06-21 15:19:32 +02:00
}
return hicon;
2004-06-21 15:19:32 +02:00
}
2003-11-25 20:29:01 +01:00
/*
* Check for a match of the window class to one specified in the
* ICONS{} section in the prefs file, and load the icon from a file
*/
HICON
hw/xwin: Make winOverrideIcon() thread-safe for icon data access winOverrideIcon() is called from the internal WM client thread. Accessing server-internal data structures to get icon data or window hints is not safe, as there is no lock to ensure we do not collide with these data structures being updated in the server thread. Rewrite so the internal client thread uses X client calls to obtain this data safely We used to also set the icon inside the server when the window was initially created. For simplicity, we simply send a message to the internal WM to update the icon when the window is created (rather than writing different icon update code which can work in the server thread for that one case...) extwm mode used to do the icon update in the server. I'm not sure that actually made much sense. Let's assume the external WM client can do it instead... v2 Make sure that WM_WM_ICON_EVENT does nothing for override-redirect windows v3 Reinstate check that native window actually has expected properties for an X window before trying to update it's icon; some auxiliary windows owned by the XWin process don't, which would cause a crash v4 Various fixes to pixmap icon conversion: - remove left-over malloc in winScaleXimageToWindowsIcon causing a memory leak - don't recalculate DDBitmap stride in winScaleXimageToWindowsIcon, when we already have worked it out - properly check that XGetWindowProperty(NET_WM_ICON) returned some data - don't try to retrieve WM_HINTS icon_mask if it isn't set - restore accidentally dropped calculation of effBpp, stride, maskStride of output DDBitmap - make sure imageMask is zero-initalized before we use it to mask the DDBitmap v5 Remove a left-over unused variable v6 Avoid XDestroyImage(NULL) crash if XGetImage failed for icon_pixmap Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk> Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
2012-07-21 15:09:16 +02:00
winOverrideIcon(char *res_name, char *res_class, char *wmName)
2003-11-25 20:29:01 +01:00
{
int i;
HICON hicon;
for (i = 0; i < pref.iconItems; i++) {
hw/xwin: Make winOverrideIcon() thread-safe for icon data access winOverrideIcon() is called from the internal WM client thread. Accessing server-internal data structures to get icon data or window hints is not safe, as there is no lock to ensure we do not collide with these data structures being updated in the server thread. Rewrite so the internal client thread uses X client calls to obtain this data safely We used to also set the icon inside the server when the window was initially created. For simplicity, we simply send a message to the internal WM to update the icon when the window is created (rather than writing different icon update code which can work in the server thread for that one case...) extwm mode used to do the icon update in the server. I'm not sure that actually made much sense. Let's assume the external WM client can do it instead... v2 Make sure that WM_WM_ICON_EVENT does nothing for override-redirect windows v3 Reinstate check that native window actually has expected properties for an X window before trying to update it's icon; some auxiliary windows owned by the XWin process don't, which would cause a crash v4 Various fixes to pixmap icon conversion: - remove left-over malloc in winScaleXimageToWindowsIcon causing a memory leak - don't recalculate DDBitmap stride in winScaleXimageToWindowsIcon, when we already have worked it out - properly check that XGetWindowProperty(NET_WM_ICON) returned some data - don't try to retrieve WM_HINTS icon_mask if it isn't set - restore accidentally dropped calculation of effBpp, stride, maskStride of output DDBitmap - make sure imageMask is zero-initalized before we use it to mask the DDBitmap v5 Remove a left-over unused variable v6 Avoid XDestroyImage(NULL) crash if XGetImage failed for icon_pixmap Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk> Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
2012-07-21 15:09:16 +02:00
if ((res_name && !strcmp(pref.icon[i].match, res_name)) ||
(res_class && !strcmp(pref.icon[i].match, res_class)) ||
(wmName && strstr(wmName, pref.icon[i].match))) {
if (pref.icon[i].hicon)
return pref.icon[i].hicon;
hicon = LoadImageComma(pref.icon[i].iconFile, pref.iconDirectory, 0, 0, LR_DEFAULTSIZE);
if (hicon == NULL)
ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n",
pref.icon[i].iconFile);
pref.icon[i].hicon = hicon;
return hicon;
}
}
2003-11-25 20:29:01 +01:00
/* Didn't find the icon, fail gracefully */
2003-11-25 20:29:01 +01:00
return 0;
}
/*
* Should we free this icon or leave it in memory (is it part of our
* ICONS{} overrides)?
*/
int
winIconIsOverride(HICON hicon)
2003-11-25 20:29:01 +01:00
{
int i;
2003-11-25 20:29:01 +01:00
if (!hicon)
return 0;
2003-11-25 20:29:01 +01:00
for (i = 0; i < pref.iconItems; i++)
if ((HICON) pref.icon[i].hicon == hicon)
return 1;
2003-11-25 20:29:01 +01:00
return 0;
}
2003-11-25 20:29:01 +01:00
/*
* Open and parse the XWinrc config file @path.
* If @path is NULL, use the built-in default.
*/
static int
winPrefsLoadPreferences(const char *path)
{
FILE *prefFile = NULL;
if (path)
prefFile = fopen(path, "r");
#ifdef __CYGWIN__
else {
char defaultPrefs[] =
"MENU rmenu {\n"
" \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n"
" \"Launch xterm\" EXEC xterm\n"
" \"Load .XWinrc\" RELOAD\n"
" SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n";
path = "built-in default";
prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r");
}
#endif
if (!prefFile) {
ErrorF("LoadPreferences: %s not found\n", path);
return FALSE;
}
ErrorF("LoadPreferences: Loading %s\n", path);
if ((parse_file(prefFile)) != 0) {
ErrorF("LoadPreferences: %s is badly formed!\n", path);
fclose(prefFile);
return FALSE;
}
fclose(prefFile);
return TRUE;
}
2003-11-25 20:29:01 +01:00
/*
* Try and open ~/.XWinrc and system.XWinrc
2003-11-25 20:29:01 +01:00
* Load it into prefs structure for use by other functions
*/
void
LoadPreferences(void)
2003-11-25 20:29:01 +01:00
{
char *home;
char fname[PATH_MAX + NAME_MAX + 2];
char szDisplay[512];
char *szEnvDisplay;
int i, j;
char param[PARAM_MAX + 1];
char *srcParam, *dstParam;
int parsed = FALSE;
/* First, clear all preference settings */
memset(&pref, 0, sizeof(pref));
/* Now try and find a ~/.xwinrc file */
home = getenv("HOME");
if (home) {
strcpy(fname, home);
if (fname[strlen(fname) - 1] != '/')
strcat(fname, "/");
strcat(fname, ".XWinrc");
parsed = winPrefsLoadPreferences(fname);
2003-11-25 20:29:01 +01:00
}
/* No home file found, check system default */
if (!parsed) {
char buffer[MAX_PATH];
#ifdef RELOCATE_PROJECTROOT
snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir());
#else
strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer));
#endif
buffer[sizeof(buffer) - 1] = 0;
parsed = winPrefsLoadPreferences(buffer);
2004-06-21 15:19:32 +02:00
}
2003-11-25 20:29:01 +01:00
/* Neither user nor system configuration found, or were badly formed */
if (!parsed) {
ErrorF
("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n");
parsed = winPrefsLoadPreferences(NULL);
2003-11-25 20:29:01 +01:00
}
/* Setup a DISPLAY environment variable, need to allocate on heap */
/* because putenv doesn't copy the argument... */
winGetDisplayName(szDisplay, 0);
szEnvDisplay = (char *) (malloc(strlen(szDisplay) + strlen("DISPLAY=") + 1));
if (szEnvDisplay) {
snprintf(szEnvDisplay, 512, "DISPLAY=%s", szDisplay);
putenv(szEnvDisplay);
2003-11-25 20:29:01 +01:00
}
/* Replace any "%display%" in menu commands with display string */
for (i = 0; i < pref.menuItems; i++) {
for (j = 0; j < pref.menu[i].menuItems; j++) {
if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) {
srcParam = pref.menu[i].menuItem[j].param;
dstParam = param;
while (*srcParam) {
if (!strncmp(srcParam, "%display%", 9)) {
memcpy(dstParam, szDisplay, strlen(szDisplay));
dstParam += strlen(szDisplay);
srcParam += 9;
}
else {
*dstParam = *srcParam;
dstParam++;
srcParam++;
}
}
*dstParam = 0;
strcpy(pref.menu[i].menuItem[j].param, param);
} /* cmd==cmd_exec */
} /* for all menuitems */
} /* for all menus */
2003-11-25 20:29:01 +01:00
}
/*
* Check for a match of the window class to one specified in the
* STYLES{} section in the prefs file, and return the style type
*/
unsigned long
winOverrideStyle(char *res_name, char *res_class, char *wmName)
{
int i;
for (i = 0; i < pref.styleItems; i++) {
if ((res_name && !strcmp(pref.style[i].match, res_name)) ||
(res_class && !strcmp(pref.style[i].match, res_class)) ||
(wmName && strstr(wmName, pref.style[i].match))) {
if (pref.style[i].type)
return pref.style[i].type;
}
}
/* Didn't find the style, fail gracefully */
return STYLE_NONE;
}