Files
wmaker/src/application.c
T
dan 41996df786 - Saving a domain file will first strip all entries that are also present in
the global domain as well and are exactly the same. This fixes a bug where
  settings from the global domain file were merged in the user domain file
  and further changes in the global domain file for those merged values was
  ignored making a system admin unable to set global defaults for all users
  using the global domains.
- Fixed bug with not extracting the icon from the client when using
  shared appicons.
- Added WMSubtractPLDictionaries() to WINGs (opposite for merging, it will
  remove all entries from dest if they are present in source and are exactly
  the same. Unique entries in dest and entries with different values from
  those present in source will be preserved).
2001-12-20 22:16:01 +00:00

503 lines
13 KiB
C

/*
* Window Maker window manager
*
* Copyright (c) 1997, 1998 Alfredo K. Kojima
* Copyright (c) 1998 Dan Pascu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include "wconfig.h"
#include <X11/Xlib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "WindowMaker.h"
#include "menu.h"
#include "window.h"
#ifdef USER_MENU
#include "usermenu.h"
#endif /* USER_MENU */
#include "icon.h"
#include "appicon.h"
#include "application.h"
#include "appmenu.h"
#include "properties.h"
#include "funcs.h"
#include "stacking.h"
#include "actions.h"
#include "defaults.h"
#include "workspace.h"
#include "dock.h"
#include "wsound.h"
/******** Global variables ********/
extern XContext wAppWinContext;
extern XContext wWinContext;
extern WPreferences wPreferences;
extern WDDomain *WDWindowAttributes;
/******** Local variables ********/
static WWindow*
makeMainWindow(WScreen *scr, Window window)
{
WWindow *wwin;
XWindowAttributes attr;
if (!XGetWindowAttributes(dpy, window, &attr)) {
return NULL;
}
wwin = wWindowCreate();
wwin->screen_ptr = scr;
wwin->client_win = window;
wwin->main_window = window;
wwin->wm_hints = XGetWMHints(dpy, window);
/* if (!MyXFetchName(dpy, window, &(wwin->frame->title))) {
wwin->frame->title = NULL;
}
*/
PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
&wwin->user_flags, &wwin->defined_user_flags, True);
XSelectInput(dpy, window, attr.your_event_mask | PropertyChangeMask
| StructureNotifyMask );
return wwin;
}
WApplication*
wApplicationOf(Window window)
{
WApplication *wapp;
if (window == None)
return NULL;
if (XFindContext(dpy, window, wAppWinContext, (XPointer*)&wapp)!=XCSUCCESS)
return NULL;
return wapp;
}
static WAppIcon*
findDockIconFor(WDock *dock, Window main_window)
{
WAppIcon *aicon = NULL;
aicon = wDockFindIconForWindow(dock, main_window);
if (!aicon) {
wDockTrackWindowLaunch(dock, main_window);
aicon = wDockFindIconForWindow(dock, main_window);
}
return aicon;
}
static void
extractIcon(WWindow *wwin)
{
int argc;
char **argv;
if (!XGetCommand(dpy, wwin->client_win, &argv, &argc) || argc < 1)
return;
wApplicationExtractDirPackIcon(wwin->screen_ptr,argv[0],
wwin->wm_instance,
wwin->wm_class);
XFreeStringList(argv);
}
static void
saveIconNameFor(char *iconPath, char *wm_instance, char *wm_class)
{
WMPropList *dict = WDWindowAttributes->dictionary;
WMPropList *adict, *key, *iconk;
WMPropList *val;
char *tmp;
int i;
i = 0;
if (wm_instance)
i += strlen(wm_instance);
if (wm_class)
i += strlen(wm_class);
tmp = wmalloc(i+8);
*tmp = 0;
if (wm_class && wm_instance) {
sprintf(tmp, "%s.%s", wm_instance, wm_class);
} else {
if (wm_instance)
strcat(tmp, wm_instance);
if (wm_class)
strcat(tmp, wm_class);
}
key = WMCreatePLString(tmp);
wfree(tmp);
adict = WMGetFromPLDictionary(dict, key);
iconk = WMCreatePLString("Icon");
if (adict) {
val = WMGetFromPLDictionary(adict, iconk);
} else {
/* no dictionary for app, so create one */
adict = WMCreatePLDictionary(NULL, NULL, NULL);
WMPutInPLDictionary(dict, key, adict);
WMReleasePropList(adict);
val = NULL;
}
if (!val) {
val = WMCreatePLString(iconPath);
WMPutInPLDictionary(adict, iconk, val);
WMReleasePropList(val);
}
WMReleasePropList(key);
WMReleasePropList(iconk);
if (val && !wPreferences.flags.noupdates) {
UpdateDomainFile(WDWindowAttributes);
}
}
void
wApplicationExtractDirPackIcon(WScreen *scr, char *path,
char *wm_instance, char *wm_class)
{
char *iconPath=NULL;
/* Maybe the app is a .app and it has an icon in it, like
* /usr/local/GNUstep/Apps/WPrefs.app/WPrefs.tiff
*/
if (strstr(path, ".app")) {
char *tmp;
tmp = wmalloc(strlen(path)+16);
if (scr->flags.supports_tiff) {
strcpy(tmp, path);
strcat(tmp, ".tiff");
if (access(tmp, R_OK)==0)
iconPath = tmp;
}
if (!path) {
strcpy(tmp, path);
strcat(tmp, ".xpm");
if (access(tmp, R_OK)==0)
iconPath = tmp;
}
if (!iconPath)
wfree(tmp);
}
if (iconPath) {
saveIconNameFor(iconPath, wm_instance, wm_class);
wfree(iconPath);
}
}
static Bool
extractClientIcon(WAppIcon *icon)
{
char *path;
path = wIconStore(icon->icon);
if (!path)
return False;
saveIconNameFor(path, icon->wm_instance, icon->wm_class);
wfree(path);
return True;
}
WApplication*
wApplicationCreate(WScreen *scr, Window main_window)
{
WApplication *wapp;
WWindow *leader;
if (main_window==None || main_window==scr->root_win) {
#ifdef DEBUG0
wwarning("trying to create application for %x",(unsigned)main_window);
#endif
return NULL;
}
{
Window root;
int foo;
unsigned int bar;
/* check if the window is valid */
if (!XGetGeometry(dpy, main_window, &root, &foo, &foo, &bar, &bar,
&bar, &bar)) {
return NULL;
}
}
wapp = wApplicationOf(main_window);
if (wapp) {
wapp->refcount++;
if (wapp->app_icon && wapp->app_icon->docked &&
wapp->app_icon->relaunching && wapp->main_window_desc->fake_group) {
wDockFinishLaunch(wapp->app_icon->dock, wapp->app_icon);
}
return wapp;
}
wapp = wmalloc(sizeof(WApplication));
memset(wapp, 0, sizeof(WApplication));
wapp->refcount = 1;
wapp->last_focused = NULL;
wapp->last_workspace = 0;
wapp->main_window = main_window;
wapp->main_window_desc = makeMainWindow(scr, main_window);
if (!wapp->main_window_desc) {
wfree(wapp);
return NULL;
}
extractIcon(wapp->main_window_desc);
leader = wWindowFor(main_window);
if (leader) {
leader->main_window = main_window;
}
wapp->menu = wAppMenuGet(scr, main_window);
#ifdef USER_MENU
if (!wapp->menu) wapp->menu = wUserMenuGet(scr, wapp->main_window_desc);
#endif /* USER_MENU */
/*
* Set application wide attributes from the leader.
*/
wapp->flags.hidden = WFLAGP(wapp->main_window_desc, start_hidden);
wapp->flags.emulated = WFLAGP(wapp->main_window_desc, emulate_appicon);
/* application descriptor */
XSaveContext(dpy, main_window, wAppWinContext, (XPointer)wapp);
if (!WFLAGP(wapp->main_window_desc, no_appicon)) {
wapp->app_icon = NULL;
if (scr->last_dock)
wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
/* check main dock if we did not find it in last dock */
if (!wapp->app_icon && scr->dock) {
wapp->app_icon = findDockIconFor(scr->dock, main_window);
}
/* finally check clips */
if (!wapp->app_icon) {
int i;
for (i=0; i<scr->workspace_count; i++) {
WDock *dock = scr->workspaces[i]->clip;
if (dock)
wapp->app_icon = findDockIconFor(dock, main_window);
if (wapp->app_icon)
break;
}
}
if (wapp->app_icon) {
WWindow *mainw = wapp->main_window_desc;
wapp->app_icon->running = 1;
wapp->app_icon->icon->force_paint = 1;
wapp->app_icon->icon->owner = mainw;
if (mainw->wm_hints && (mainw->wm_hints->flags&IconWindowHint))
wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
wAppIconPaint(wapp->app_icon);
} else {
wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
}
} else {
wapp->app_icon = NULL;
}
if (wapp->app_icon) {
wapp->app_icon->main_window = main_window;
}
if (wapp->app_icon && !wapp->app_icon->docked) {
WIcon *icon = wapp->app_icon->icon;
WDock *clip = scr->workspaces[scr->current_workspace]->clip;
int x=0, y=0;
if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
wapp->app_icon->attracted = 1;
if (!icon->shadowed) {
icon->shadowed = 1;
icon->force_paint = 1;
/* wAppIconPaint() is done in wDockAttachIcon() below */
}
wDockAttachIcon(clip, wapp->app_icon, x, y);
} else {
PlaceIcon(scr, &x, &y);
wAppIconMove(wapp->app_icon, x, y);
wLowerFrame(icon->core);
}
if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
XMapWindow(dpy, icon->core->window);
}
if (wPreferences.auto_arrange_icons && wapp->app_icon && !wapp->app_icon->attracted) {
wArrangeIcons(scr, True);
}
if (wapp->app_icon) {
char *tmp, *path;
struct stat dummy;
RImage *image;
tmp = wDefaultGetIconFile(scr, wapp->app_icon->wm_instance,
wapp->app_icon->wm_class, True);
/* If the icon was saved by us from the client supplied icon, but is
* missing, recreate it. */
if (tmp && strstr(tmp, ".AppInfo/WindowMaker")!=NULL &&
stat(tmp, &dummy)!=0 && errno==ENOENT) {
wmessage(_("recreating missing icon '%s'"), tmp);
path = wIconStore(wapp->app_icon->icon);
if (path) {
wfree(path);
}
image = wDefaultGetImage(scr, wapp->app_icon->wm_instance,
wapp->app_icon->wm_class);
if (image) {
wIconChangeImage(wapp->app_icon->icon, image);
wAppIconPaint(wapp->app_icon);
/* TODO:
* wIconChangeImage() should be rewriten to use retain/release
* The way it is now is too confusing about where the icon is
* finally released. -Dan */
/* --this is wrong at the moment-- RReleaseImage(image);*/
}
}
/* if the displayed icon was supplied by the client, save the icon */
if (!tmp)
extractClientIcon(wapp->app_icon);
}
wSoundPlay(WSOUND_APPSTART);
#ifdef DEBUG
printf("Created application for %x\n", (unsigned)main_window);
#endif
return wapp;
}
void
wApplicationDestroy(WApplication *wapp)
{
Window main_window;
WWindow *wwin;
WScreen *scr;
if (!wapp)
return;
wapp->refcount--;
if (wapp->refcount>0)
return;
scr = wapp->main_window_desc->screen_ptr;
main_window = wapp->main_window;
if (wapp == scr->wapp_list) {
if (wapp->next)
wapp->next->prev = NULL;
scr->wapp_list = wapp->next;
} else {
if (wapp->next)
wapp->next->prev = wapp->prev;
if (wapp->prev)
wapp->prev->next = wapp->next;
}
XDeleteContext(dpy, wapp->main_window, wAppWinContext);
wAppMenuDestroy(wapp->menu);
if (wapp->app_icon) {
if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
wapp->app_icon->running = 0;
/* since we keep it, we don't care if it was attracted or not */
wapp->app_icon->attracted = 0;
wapp->app_icon->icon->shadowed = 0;
wapp->app_icon->main_window = None;
wapp->app_icon->pid = 0;
wapp->app_icon->icon->owner = NULL;
wapp->app_icon->icon->icon_win = None;
wapp->app_icon->icon->force_paint = 1;
wAppIconPaint(wapp->app_icon);
} else if (wapp->app_icon->docked) {
wapp->app_icon->running = 0;
wDockDetach(wapp->app_icon->dock, wapp->app_icon);
} else {
wAppIconDestroy(wapp->app_icon);
}
}
wwin = wWindowFor(wapp->main_window_desc->client_win);
wWindowDestroy(wapp->main_window_desc);
if (wwin) {
/* undelete client window context that was deleted in
* wWindowDestroy */
XSaveContext(dpy, wwin->client_win, wWinContext,
(XPointer)&wwin->client_descriptor);
}
wfree(wapp);
#ifdef DEBUG
printf("Destroyed application for %x\n", (unsigned)main_window);
#endif
if (wPreferences.auto_arrange_icons) {
wArrangeIcons(scr, True);
}
wSoundPlay(WSOUND_APPEXIT);
}