Updating to version 0.20.2
[wmaker-crm.git] / src / application.c
blob49aeec61aae09e4b99481e3af8445bd3d58a01fb
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
29 #include "WindowMaker.h"
30 #include "menu.h"
31 #include "window.h"
32 #include "icon.h"
33 #include "appicon.h"
34 #include "application.h"
35 #include "appmenu.h"
36 #include "properties.h"
37 #include "funcs.h"
38 #include "stacking.h"
39 #include "actions.h"
40 #include "defaults.h"
41 #include "workspace.h"
43 #include "dock.h"
45 #ifdef WMSOUND
46 #include "wmsound.h"
47 #endif
50 /******** Global variables ********/
52 extern XContext wAppWinContext;
53 extern XContext wWinContext;
54 extern WPreferences wPreferences;
56 extern WDDomain *WDWindowAttributes;
58 /******** Local variables ********/
61 static WWindow*
62 makeMainWindow(WScreen *scr, Window window)
64 WWindow *wwin;
65 XWindowAttributes attr;
68 if (!XGetWindowAttributes(dpy, window, &attr)) {
69 return NULL;
72 wwin = wWindowCreate();
73 wwin->screen_ptr = scr;
74 wwin->client_win = window;
75 wwin->main_window = window;
76 wwin->wm_hints = XGetWMHints(dpy, window);
77 /* if (!MyXFetchName(dpy, window, &(wwin->frame->title))) {
78 wwin->frame->title = NULL;
81 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
83 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
84 &wwin->window_flags, True);
86 XSelectInput(dpy, window, attr.your_event_mask | PropertyChangeMask
87 | StructureNotifyMask );
88 return wwin;
92 WApplication*
93 wApplicationOf(Window window)
95 WApplication *wapp;
97 if (window == None)
98 return NULL;
99 if (XFindContext(dpy, window, wAppWinContext, (XPointer*)&wapp)!=XCSUCCESS)
100 return NULL;
101 return wapp;
105 static WAppIcon*
106 findDockIconFor(WDock *dock, Window main_window)
108 WAppIcon *aicon = NULL;
110 aicon = wDockFindIconFor(dock, main_window);
111 if (!aicon) {
112 wDockTrackWindowLaunch(dock, main_window);
113 aicon = wDockFindIconFor(dock, main_window);
115 return aicon;
119 static void
120 extractIcon(WWindow *wwin)
122 int argc;
123 char **argv;
125 if (!XGetCommand(dpy, wwin->client_win, &argv, &argc) || argc < 1)
126 return;
128 wApplicationExtractDirPackIcon(wwin->screen_ptr,argv[0],
129 wwin->wm_instance,
130 wwin->wm_class);
131 XFreeStringList(argv);
135 static void
136 saveIconNameFor(char *iconPath, char *wm_instance, char *wm_class)
138 proplist_t dict = WDWindowAttributes->dictionary;
139 proplist_t adict, key, iconk;
140 proplist_t val;
141 char *tmp;
142 int i;
144 i = 0;
145 if (wm_instance)
146 i += strlen(wm_instance);
147 if (wm_class)
148 i += strlen(wm_class);
150 tmp = wmalloc(i+8);
151 *tmp = 0;
152 if (wm_class && wm_instance) {
153 sprintf(tmp, "%s.%s", wm_instance, wm_class);
154 } else {
155 if (wm_instance)
156 strcat(tmp, wm_instance);
157 if (wm_class)
158 strcat(tmp, wm_class);
161 key = PLMakeString(tmp);
162 free(tmp);
163 adict = PLGetDictionaryEntry(dict, key);
165 iconk = PLMakeString("Icon");
167 if (adict) {
168 val = PLGetDictionaryEntry(adict, iconk);
169 } else {
170 /* no dictionary for app, so create one */
171 adict = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
172 PLInsertDictionaryEntry(dict, key, adict);
173 PLRelease(adict);
174 val = NULL;
176 if (!val) {
177 val = PLMakeString(iconPath);
178 PLInsertDictionaryEntry(adict, iconk, val);
179 PLRelease(val);
181 PLRelease(key);
183 if (val)
184 PLSave(dict, YES);
188 void
189 wApplicationExtractDirPackIcon(WScreen *scr, char *path,
190 char *wm_instance, char *wm_class)
192 char *iconPath=NULL;
193 /* Maybe the app is a .app and it has an icon in it, like
194 * /usr/local/GNUstep/Apps/WPrefs.app/WPrefs.tiff
196 if (strstr(path, ".app")) {
197 char *tmp;
199 tmp = wmalloc(strlen(path)+16);
201 if (scr->flags.supports_tiff) {
202 strcpy(tmp, path);
203 strcat(tmp, ".tiff");
204 if (access(tmp, R_OK)==0)
205 iconPath = tmp;
207 if (!path) {
208 strcpy(tmp, path);
209 strcat(tmp, ".xpm");
210 if (access(tmp, R_OK)==0)
211 iconPath = tmp;
213 if (!iconPath)
214 free(tmp);
217 if (iconPath) {
218 saveIconNameFor(iconPath, wm_instance, wm_class);
220 free(iconPath);
225 static Bool
226 extractClientIcon(WAppIcon *icon)
228 char *path;
230 path = wIconStore(icon->icon);
231 if (!path)
232 return False;
234 saveIconNameFor(path, icon->wm_instance, icon->wm_class);
236 free(path);
238 return True;
242 WApplication*
243 wApplicationCreate(WScreen *scr, Window main_window)
245 WApplication *wapp;
246 WWindow *leader;
248 if (main_window==None || main_window==scr->root_win) {
249 #ifdef DEBUG0
250 wwarning("trying to create application for %x",(unsigned)main_window);
251 #endif
252 return NULL;
256 Window root;
257 int foo;
258 unsigned int bar;
259 /* check if the window is valid */
260 if (!XGetGeometry(dpy, main_window, &root, &foo, &foo, &bar, &bar,
261 &bar, &bar)) {
262 return NULL;
266 wapp = wApplicationOf(main_window);
267 if (wapp) {
268 wapp->refcount++;
269 return wapp;
272 wapp = wmalloc(sizeof(WApplication));
273 memset(wapp, 0, sizeof(WApplication));
275 wapp->refcount = 1;
276 wapp->last_focused = NULL;
278 wapp->last_workspace = 0;
280 wapp->main_window = main_window;
281 wapp->main_window_desc = makeMainWindow(scr, main_window);
282 if (!wapp->main_window_desc) {
283 free(wapp);
284 return NULL;
287 extractIcon(wapp->main_window_desc);
289 leader = wWindowFor(main_window);
290 if (leader) {
291 leader->main_window = main_window;
293 wapp->menu = wAppMenuGet(scr, main_window);
297 * Set application wide attributes from the leader.
299 wapp->flags.hidden = wapp->main_window_desc->window_flags.start_hidden;
301 wapp->flags.emulated = wapp->main_window_desc->window_flags.emulate_appicon;
303 /* application descriptor */
304 XSaveContext(dpy, main_window, wAppWinContext, (XPointer)wapp);
306 if (!wapp->main_window_desc->window_flags.no_appicon) {
307 wapp->app_icon = NULL;
308 if (scr->last_dock)
309 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
310 /* check main dock if we did not find it in last dock */
311 if (!wapp->app_icon && scr->dock)
312 wapp->app_icon = findDockIconFor(scr->dock, main_window);
313 /* finally check clips */
314 if (!wapp->app_icon) {
315 int i;
316 for (i=0; i<scr->workspace_count; i++) {
317 WDock *dock = scr->workspaces[i]->clip;
318 if (dock)
319 wapp->app_icon = findDockIconFor(dock, main_window);
320 if (wapp->app_icon)
321 break;
325 if (wapp->app_icon) {
326 WWindow *mainw = wapp->main_window_desc;
328 wapp->app_icon->running = 1;
329 wapp->app_icon->icon->force_paint = 1;
330 wapp->app_icon->icon->owner = mainw;
331 if (mainw->wm_hints && (mainw->wm_hints->flags&IconWindowHint))
332 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
333 wAppIconPaint(wapp->app_icon);
334 } else {
335 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
336 #ifdef REDUCE_APPICONS
337 /* This is so we get the appearance of invoking the app sitting
338 * on the dock. -cls */
339 if (wapp->app_icon) {
340 if (wapp->app_icon->docked && wapp->app_icon->num_apps == 1) {
341 wapp->app_icon->launching = 0;
342 wapp->app_icon->running = 1;
343 wapp->app_icon->icon->force_paint = 1;
344 wAppIconPaint(wapp->app_icon);
347 #endif
349 } else {
350 wapp->app_icon = NULL;
353 if (wapp->app_icon) {
354 wapp->app_icon->main_window = main_window;
355 #ifdef WMSOUND
356 wSoundServerGrab(wapp->app_icon->wm_class, main_window);
357 #endif
360 #ifndef REDUCE_APPICONS
361 if (wapp->app_icon && !wapp->app_icon->docked) {
362 #else
363 if (wapp->app_icon && !wapp->app_icon->docked && wapp->app_icon->num_apps == 1) {
364 #ifdef THIS_SUCKS
366 #endif
367 #endif
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 (!clip->keep_attracted && !wapp->app_icon->icon->shadowed) {
375 wapp->app_icon->icon->shadowed = 1;
376 wapp->app_icon->icon->force_paint = 1;
377 /* We don't do an wAppIconPaint() here because it's in
378 * wDockAttachIcon(). -Dan.
381 wDockAttachIcon(clip, wapp->app_icon, x, y);
382 } else {
383 PlaceIcon(scr, &x, &y);
384 wAppIconMove(wapp->app_icon, x, y);
385 #ifndef STRICTNS
386 wLowerFrame(icon->core);
387 #endif
389 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
390 XMapWindow(dpy, icon->core->window);
393 if (wPreferences.auto_arrange_icons && wapp->app_icon && !wapp->app_icon->attracted) {
394 wArrangeIcons(scr, True);
397 if (wapp->app_icon) {
398 char *tmp;
400 /* if the displayed icon was supplied by the client, save the icon */
401 tmp = wDefaultGetIconFile(scr, wapp->app_icon->wm_instance,
402 wapp->app_icon->wm_class, True);
403 if (!tmp)
404 extractClientIcon(wapp->app_icon);
407 wapp->prev = NULL;
408 wapp->next = scr->wapp_list;
409 if (scr->wapp_list)
410 scr->wapp_list->prev = wapp;
411 scr->wapp_list = wapp;
413 #ifdef WMSOUND
414 wSoundPlay(WMSOUND_APPSTART);
415 #endif
417 #ifdef DEBUG
418 printf("Created application for %x\n", (unsigned)main_window);
419 #endif
420 return wapp;
424 void
425 wApplicationDestroy(WApplication *wapp)
427 Window main_window;
428 WWindow *wwin;
429 WScreen *scr;
430 #ifdef REDUCE_APPICONS
431 unsigned int napps;
432 #endif
434 if (!wapp)
435 return;
437 wapp->refcount--;
438 if (wapp->refcount>0)
439 return;
442 scr = wapp->main_window_desc->screen_ptr;
443 main_window = wapp->main_window;
444 #ifdef REDUCE_APPICONS
445 napps = wAppIconReduceAppCount(wapp);
446 #endif
448 if (wapp == scr->wapp_list) {
449 if (wapp->next)
450 wapp->next->prev = NULL;
451 scr->wapp_list = wapp->next;
452 } else {
453 if (wapp->next)
454 wapp->next->prev = wapp->prev;
455 if (wapp->prev)
456 wapp->prev->next = wapp->next;
459 XDeleteContext(dpy, wapp->main_window, wAppWinContext);
460 wAppMenuDestroy(wapp->menu);
461 if (wapp->app_icon) {
462 if (wapp->app_icon->docked
463 && (!wapp->app_icon->attracted ||
464 wapp->app_icon->dock->keep_attracted)) {
465 #ifdef REDUCE_APPICONS
466 if (napps == 0) {
467 #endif
468 wapp->app_icon->running = 0;
469 /* since we keep it, we don't care if it was attracted or not */
470 wapp->app_icon->attracted = 0;
471 wapp->app_icon->icon->shadowed = 0;
472 wapp->app_icon->main_window = None;
473 wapp->app_icon->pid = 0;
474 wapp->app_icon->icon->owner = NULL;
475 wapp->app_icon->icon->icon_win = None;
476 wapp->app_icon->icon->force_paint = 1;
477 wAppIconPaint(wapp->app_icon);
478 #ifdef REDUCE_APPICONS
480 #endif
481 } else if (wapp->app_icon->docked) {
482 #ifdef REDUCE_APPICONS
483 if (napps == 0) {
484 #endif
485 wapp->app_icon->running = 0;
486 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
487 #ifdef REDUCE_APPICONS
489 #endif
490 } else {
491 #ifdef REDUCE_APPICONS
492 if (napps == 0) {
493 #endif
494 wAppIconDestroy(wapp->app_icon);
495 #ifdef REDUCE_APPICONS
497 #endif
500 wwin = wWindowFor(wapp->main_window_desc->client_win);
502 wWindowDestroy(wapp->main_window_desc);
503 if (wwin) {
504 /* undelete client window context that was deleted in
505 * wWindowDestroy */
506 XSaveContext(dpy, wwin->client_win, wWinContext,
507 (XPointer)&wwin->client_descriptor);
509 free(wapp);
511 #ifdef DEBUG
512 printf("Destroyed application for %x\n", (unsigned)main_window);
513 #endif
514 if (wPreferences.auto_arrange_icons) {
515 wArrangeIcons(scr, True);
518 #ifdef WMSOUND
519 wSoundPlay(WMSOUND_APPEXIT);
520 #endif