applied patch to rename .AppInfo directory
[wmaker-crm.git] / src / application.c
blobad5d388cc2faaeac69e5fab69bc2b833bd6657e9
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 * Copyright (c) 1998-2003 Dan Pascu
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <errno.h>
34 #include "WindowMaker.h"
35 #include "menu.h"
36 #include "window.h"
37 #ifdef USER_MENU
38 #include "usermenu.h"
39 #endif /* USER_MENU */
40 #include "icon.h"
41 #include "appicon.h"
42 #include "application.h"
43 #include "appmenu.h"
44 #include "properties.h"
45 #include "funcs.h"
46 #include "stacking.h"
47 #include "actions.h"
48 #include "defaults.h"
49 #include "workspace.h"
50 #include "dock.h"
51 #include "wsound.h"
53 #include "xinerama.h"
56 /******** Global variables ********/
58 extern XContext wAppWinContext;
59 extern XContext wWinContext;
60 extern WPreferences wPreferences;
62 extern WDDomain *WDWindowAttributes;
64 /******** Local variables ********/
67 static WWindow*
68 makeMainWindow(WScreen *scr, Window window)
70 WWindow *wwin;
71 XWindowAttributes attr;
73 if (!XGetWindowAttributes(dpy, window, &attr)) {
74 return NULL;
77 wwin = wWindowCreate();
78 wwin->screen_ptr = scr;
79 wwin->client_win = window;
80 wwin->main_window = window;
81 wwin->wm_hints = XGetWMHints(dpy, window);
82 /* if (!MyXFetchName(dpy, window, &(wwin->frame->title))) {
83 wwin->frame->title = NULL;
86 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
89 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
90 &wwin->user_flags, &wwin->defined_user_flags, True);
92 XSelectInput(dpy, window, attr.your_event_mask | PropertyChangeMask
93 | StructureNotifyMask);
94 return wwin;
98 WApplication*
99 wApplicationOf(Window window)
101 WApplication *wapp;
103 if (window == None)
104 return NULL;
105 if (XFindContext(dpy, window, wAppWinContext, (XPointer*)&wapp)!=XCSUCCESS)
106 return NULL;
107 return wapp;
111 static WAppIcon*
112 findDockIconFor(WDock *dock, Window main_window)
114 WAppIcon *aicon = NULL;
116 aicon = wDockFindIconForWindow(dock, main_window);
117 if (!aicon) {
118 wDockTrackWindowLaunch(dock, main_window);
119 aicon = wDockFindIconForWindow(dock, main_window);
121 return aicon;
125 static void
126 extractIcon(WWindow *wwin)
128 char *progname;
130 progname = GetProgramNameForWindow(wwin->client_win);
131 if (progname) {
132 wApplicationExtractDirPackIcon(wwin->screen_ptr, progname,
133 wwin->wm_instance, wwin->wm_class);
134 wfree(progname);
139 static void
140 saveIconNameFor(char *iconPath, char *wm_instance, char *wm_class)
142 WMPropList *dict = WDWindowAttributes->dictionary;
143 WMPropList *adict, *key, *iconk;
144 WMPropList *val;
145 char *tmp;
146 int i;
148 i = 0;
149 if (wm_instance)
150 i += strlen(wm_instance);
151 if (wm_class)
152 i += strlen(wm_class);
154 tmp = wmalloc(i+8);
155 *tmp = 0;
156 if (wm_class && wm_instance) {
157 sprintf(tmp, "%s.%s", wm_instance, wm_class);
158 } else {
159 if (wm_instance)
160 strcat(tmp, wm_instance);
161 if (wm_class)
162 strcat(tmp, wm_class);
165 key = WMCreatePLString(tmp);
166 wfree(tmp);
167 adict = WMGetFromPLDictionary(dict, key);
169 iconk = WMCreatePLString("Icon");
171 if (adict) {
172 val = WMGetFromPLDictionary(adict, iconk);
173 } else {
174 /* no dictionary for app, so create one */
175 adict = WMCreatePLDictionary(NULL, NULL);
176 WMPutInPLDictionary(dict, key, adict);
177 WMReleasePropList(adict);
178 val = NULL;
180 if (!val) {
181 val = WMCreatePLString(iconPath);
182 WMPutInPLDictionary(adict, iconk, val);
183 WMReleasePropList(val);
185 WMReleasePropList(key);
186 WMReleasePropList(iconk);
188 if (val && !wPreferences.flags.noupdates) {
189 UpdateDomainFile(WDWindowAttributes);
194 void
195 wApplicationExtractDirPackIcon(WScreen *scr, char *path,
196 char *wm_instance, char *wm_class)
198 char *iconPath=NULL;
199 /* Maybe the app is a .app and it has an icon in it, like
200 * /usr/local/GNUstep/Applications/WPrefs.app/WPrefs.tiff
202 if (strstr(path, ".app")) {
203 char *tmp;
205 tmp = wmalloc(strlen(path)+16);
207 if (scr->flags.supports_tiff) {
208 strcpy(tmp, path);
209 strcat(tmp, ".tiff");
210 if (access(tmp, R_OK)==0)
211 iconPath = tmp;
213 if (!path) {
214 strcpy(tmp, path);
215 strcat(tmp, ".xpm");
216 if (access(tmp, R_OK)==0)
217 iconPath = tmp;
219 if (!iconPath)
220 wfree(tmp);
223 if (iconPath) {
224 saveIconNameFor(iconPath, wm_instance, wm_class);
226 wfree(iconPath);
231 static Bool
232 extractClientIcon(WAppIcon *icon)
234 char *path;
236 path = wIconStore(icon->icon);
237 if (!path)
238 return False;
240 saveIconNameFor(path, icon->wm_instance, icon->wm_class);
242 wfree(path);
244 return True;
248 WApplication*
249 wApplicationCreate(WWindow *wwin)
251 WScreen *scr = wwin->screen_ptr;
252 Window main_window = wwin->main_window;
253 WApplication *wapp;
254 WWindow *leader;
256 if (main_window==None || main_window==scr->root_win) {
257 #ifdef DEBUG0
258 wwarning("trying to create application for %x",(unsigned)main_window);
259 #endif
260 return NULL;
264 Window root;
265 int foo;
266 unsigned int bar;
267 /* check if the window is valid */
268 if (!XGetGeometry(dpy, main_window, &root, &foo, &foo, &bar, &bar,
269 &bar, &bar)) {
270 return NULL;
274 wapp = wApplicationOf(main_window);
275 if (wapp) {
276 wapp->refcount++;
277 if (wapp->app_icon && wapp->app_icon->docked &&
278 wapp->app_icon->relaunching && wapp->main_window_desc->fake_group) {
279 wDockFinishLaunch(wapp->app_icon->dock, wapp->app_icon);
282 return wapp;
285 wapp = wmalloc(sizeof(WApplication));
286 memset(wapp, 0, sizeof(WApplication));
288 wapp->refcount = 1;
289 wapp->last_focused = NULL;
291 wapp->last_workspace = 0;
293 wapp->main_window = main_window;
294 wapp->main_window_desc = makeMainWindow(scr, main_window);
295 if (!wapp->main_window_desc) {
296 wfree(wapp);
297 return NULL;
300 wapp->main_window_desc->fake_group = wwin->fake_group;
301 #ifdef NETWM_HINTS
302 wapp->main_window_desc->net_icon_image = RRetainImage(wwin->net_icon_image);
303 #endif
305 extractIcon(wapp->main_window_desc);
307 leader = wWindowFor(main_window);
308 if (leader) {
309 leader->main_window = main_window;
311 wapp->menu = wAppMenuGet(scr, main_window);
312 #ifdef USER_MENU
313 if (!wapp->menu) wapp->menu = wUserMenuGet(scr, wapp->main_window_desc);
314 #endif /* USER_MENU */
318 * Set application wide attributes from the leader.
320 wapp->flags.hidden = WFLAGP(wapp->main_window_desc, start_hidden);
322 wapp->flags.emulated = WFLAGP(wapp->main_window_desc, emulate_appicon);
324 /* application descriptor */
325 XSaveContext(dpy, main_window, wAppWinContext, (XPointer)wapp);
327 if (!WFLAGP(wapp->main_window_desc, no_appicon)) {
328 wapp->app_icon = NULL;
329 if (scr->last_dock)
330 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
331 /* check main dock if we did not find it in last dock */
332 if (!wapp->app_icon && scr->dock) {
333 wapp->app_icon = findDockIconFor(scr->dock, main_window);
335 /* finally check clips */
336 if (!wapp->app_icon) {
337 int i;
338 for (i=0; i<scr->workspace_count; i++) {
339 WDock *dock = scr->workspaces[i]->clip;
340 if (dock)
341 wapp->app_icon = findDockIconFor(dock, main_window);
342 if (wapp->app_icon)
343 break;
347 if (wapp->app_icon) {
348 WWindow *mainw = wapp->main_window_desc;
350 wapp->app_icon->running = 1;
351 wapp->app_icon->icon->force_paint = 1;
352 wapp->app_icon->icon->owner = mainw;
353 if (mainw->wm_hints && (mainw->wm_hints->flags&IconWindowHint))
354 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
355 wAppIconPaint(wapp->app_icon);
356 } else {
357 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
359 } else {
360 wapp->app_icon = NULL;
363 if (wapp->app_icon) {
364 wapp->app_icon->main_window = main_window;
367 if (wapp->app_icon && !wapp->app_icon->docked) {
368 WIcon *icon = wapp->app_icon->icon;
369 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
370 int x=0, y=0;
372 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
373 wapp->app_icon->attracted = 1;
374 if (!icon->shadowed) {
375 icon->shadowed = 1;
376 icon->force_paint = 1;
377 /* wAppIconPaint() is done in wDockAttachIcon() below */
379 wDockAttachIcon(clip, wapp->app_icon, x, y);
380 } else {
381 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wapp->main_window_desc));
382 wAppIconMove(wapp->app_icon, x, y);
383 wLowerFrame(icon->core);
385 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
386 XMapWindow(dpy, icon->core->window);
389 if (wPreferences.auto_arrange_icons && wapp->app_icon && !wapp->app_icon->attracted) {
390 wArrangeIcons(scr, True);
393 if (wapp->app_icon) {
394 char *tmp, *path;
395 struct stat dummy;
396 RImage *image;
398 tmp = wDefaultGetIconFile(scr, wapp->app_icon->wm_instance,
399 wapp->app_icon->wm_class, True);
401 /* If the icon was saved by us from the client supplied icon, but is
402 * missing, recreate it. */
403 if (tmp && strstr(tmp, "Library/WindowMaker/CachedPixmaps")!=NULL &&
404 stat(tmp, &dummy)!=0 && errno==ENOENT) {
405 wmessage(_("recreating missing icon '%s'"), tmp);
406 path = wIconStore(wapp->app_icon->icon);
407 if (path) {
408 wfree(path);
410 image = wDefaultGetImage(scr, wapp->app_icon->wm_instance,
411 wapp->app_icon->wm_class);
412 if (image) {
413 wIconChangeImage(wapp->app_icon->icon, image);
414 wAppIconPaint(wapp->app_icon);
415 /* TODO:
416 * wIconChangeImage() should be rewriten to use retain/release
417 * The way it is now is too confusing about where the icon is
418 * finally released. -Dan */
419 /* --this is wrong at the moment-- RReleaseImage(image);*/
423 /* if the displayed icon was supplied by the client, save the icon */
424 if (!tmp)
425 extractClientIcon(wapp->app_icon);
428 wSoundPlay(WSOUND_APPSTART);
430 #ifdef DEBUG
431 printf("Created application for %x\n", (unsigned)main_window);
432 #endif
433 return wapp;
437 void
438 wApplicationDestroy(WApplication *wapp)
440 Window main_window;
441 WWindow *wwin;
442 WScreen *scr;
444 if (!wapp)
445 return;
447 wapp->refcount--;
448 if (wapp->refcount>0)
449 return;
452 scr = wapp->main_window_desc->screen_ptr;
453 main_window = wapp->main_window;
455 if (wapp == scr->wapp_list) {
456 if (wapp->next)
457 wapp->next->prev = NULL;
458 scr->wapp_list = wapp->next;
459 } else {
460 if (wapp->next)
461 wapp->next->prev = wapp->prev;
462 if (wapp->prev)
463 wapp->prev->next = wapp->next;
466 XDeleteContext(dpy, wapp->main_window, wAppWinContext);
467 wAppMenuDestroy(wapp->menu);
468 if (wapp->app_icon) {
469 if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
470 wapp->app_icon->running = 0;
471 /* since we keep it, we don't care if it was attracted or not */
472 wapp->app_icon->attracted = 0;
473 wapp->app_icon->icon->shadowed = 0;
474 wapp->app_icon->main_window = None;
475 wapp->app_icon->pid = 0;
476 wapp->app_icon->icon->owner = NULL;
477 wapp->app_icon->icon->icon_win = None;
478 wapp->app_icon->icon->force_paint = 1;
479 wAppIconPaint(wapp->app_icon);
480 } else if (wapp->app_icon->docked) {
481 wapp->app_icon->running = 0;
482 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
483 } else {
484 wAppIconDestroy(wapp->app_icon);
487 wwin = wWindowFor(wapp->main_window_desc->client_win);
489 wWindowDestroy(wapp->main_window_desc);
490 if (wwin) {
491 /* undelete client window context that was deleted in
492 * wWindowDestroy */
493 XSaveContext(dpy, wwin->client_win, wWinContext,
494 (XPointer)&wwin->client_descriptor);
496 wfree(wapp);
498 #ifdef DEBUG
499 printf("Destroyed application for %x\n", (unsigned)main_window);
500 #endif
501 if (wPreferences.auto_arrange_icons) {
502 wArrangeIcons(scr, True);
505 wSoundPlay(WSOUND_APPEXIT);