Initial revision
[wmaker-crm.git] / src / application.c
blobf5fceb3086640fb6c352c266318fed986228dab1
1 /*
2 * WindowMaker 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 void
136 wApplicationExtractDirPackIcon(WScreen *scr, char *path,
137 char *wm_instance, char *wm_class)
139 char *iconPath=NULL;
140 /* Maybe the app is a .app and it has an icon in it, like
141 * /usr/local/GNUstep/Apps/WPrefs.app/WPrefs.tiff
143 if (strstr(path, ".app")) {
144 char *tmp;
146 tmp = wmalloc(strlen(path)+16);
148 if (scr->flags.supports_tiff) {
149 strcpy(tmp, path);
150 strcat(tmp, ".tiff");
151 if (access(tmp, R_OK)==0)
152 iconPath = tmp;
154 if (!path) {
155 strcpy(tmp, path);
156 strcat(tmp, ".xpm");
157 if (access(tmp, R_OK)==0)
158 iconPath = tmp;
160 if (!iconPath)
161 free(tmp);
164 if (iconPath) {
165 proplist_t dict = WDWindowAttributes->dictionary;
166 proplist_t adict, key, iconk;
167 proplist_t val;
168 char *tmp;
169 int i;
171 i = 0;
172 if (wm_instance)
173 i += strlen(wm_instance);
174 if (wm_class)
175 i += strlen(wm_class);
177 tmp = wmalloc(i+8);
178 *tmp = 0;
179 if (wm_class && wm_instance) {
180 sprintf(tmp, "%s.%s", wm_instance, wm_class);
181 } else {
182 if (wm_instance)
183 strcat(tmp, wm_instance);
184 if (wm_class)
185 strcat(tmp, wm_class);
188 key = PLMakeString(tmp);
189 free(tmp);
190 adict = PLGetDictionaryEntry(dict, key);
192 iconk = PLMakeString("Icon");
194 if (adict) {
195 val = PLGetDictionaryEntry(adict, iconk);
196 } else {
197 /* no dictionary for app, so create one */
198 adict = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
199 PLInsertDictionaryEntry(dict, key, adict);
200 PLRelease(adict);
201 val = NULL;
203 if (!val) {
204 val = PLMakeString(iconPath);
205 PLInsertDictionaryEntry(adict, iconk, val);
206 PLRelease(val);
208 PLRelease(key);
210 if (val)
211 PLSave(dict, YES);
213 free(iconPath);
218 WApplication*
219 wApplicationCreate(WScreen *scr, Window main_window)
221 WApplication *wapp;
222 WWindow *leader;
224 if (main_window==None || main_window==scr->root_win) {
225 #ifdef DEBUG0
226 wwarning("trying to create application for %x",(unsigned)main_window);
227 #endif
228 return NULL;
232 Window root;
233 int foo;
234 unsigned int bar;
235 /* check if the window is valid */
236 if (!XGetGeometry(dpy, main_window, &root, &foo, &foo, &bar, &bar,
237 &bar, &bar)) {
238 return NULL;
242 wapp = wApplicationOf(main_window);
243 if (wapp) {
244 wapp->refcount++;
245 return wapp;
248 wapp = wmalloc(sizeof(WApplication));
249 memset(wapp, 0, sizeof(WApplication));
251 wapp->refcount = 1;
252 wapp->last_focused = NULL;
254 wapp->last_workspace = 0;
256 wapp->main_window = main_window;
257 wapp->main_window_desc = makeMainWindow(scr, main_window);
258 if (!wapp->main_window_desc) {
259 free(wapp);
260 return NULL;
263 extractIcon(wapp->main_window_desc);
265 leader = wWindowFor(main_window);
266 if (leader) {
267 leader->main_window = main_window;
269 wapp->menu = wAppMenuGet(scr, main_window);
273 * Set application wide attributes from the leader.
275 wapp->flags.hidden = wapp->main_window_desc->window_flags.start_hidden;
277 wapp->flags.emulated = wapp->main_window_desc->window_flags.emulate_appicon;
279 /* application descriptor */
280 XSaveContext(dpy, main_window, wAppWinContext, (XPointer)wapp);
282 if (!wapp->main_window_desc->window_flags.no_appicon) {
283 wapp->app_icon = NULL;
284 if (scr->last_dock)
285 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
286 /* check main dock if we did not find it in last dock */
287 if (!wapp->app_icon && scr->dock)
288 wapp->app_icon = findDockIconFor(scr->dock, main_window);
289 /* finally check clips */
290 if (!wapp->app_icon) {
291 int i;
292 for (i=0; i<scr->workspace_count; i++) {
293 WDock *dock = scr->workspaces[i]->clip;
294 if (dock)
295 wapp->app_icon = findDockIconFor(dock, main_window);
296 if (wapp->app_icon)
297 break;
301 if (wapp->app_icon) {
302 WWindow *mainw = wapp->main_window_desc;
304 wapp->app_icon->running = 1;
305 wapp->app_icon->icon->force_paint = 1;
306 wapp->app_icon->icon->owner = mainw;
307 if (mainw->wm_hints && (mainw->wm_hints->flags&IconWindowHint))
308 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
309 wAppIconPaint(wapp->app_icon);
310 } else {
311 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
312 #ifdef REDUCE_APPICONS
313 /* This is so we get the appearance of invoking the app sitting
314 * on the dock. -cls */
315 if (wapp->app_icon) {
316 if (wapp->app_icon->docked && wapp->app_icon->num_apps == 1) {
317 wapp->app_icon->launching = 0;
318 wapp->app_icon->running = 1;
319 wapp->app_icon->icon->force_paint = 1;
320 wAppIconPaint(wapp->app_icon);
323 #endif
325 } else {
326 wapp->app_icon = NULL;
329 if (wapp->app_icon) {
330 wapp->app_icon->main_window = main_window;
331 #ifdef WMSOUND
332 wSoundServerGrab(wapp->app_icon->wm_class, main_window);
333 #endif
336 #ifndef REDUCE_APPICONS
337 if (wapp->app_icon && !wapp->app_icon->docked) {
338 #else
339 if (wapp->app_icon && !wapp->app_icon->docked && wapp->app_icon->num_apps == 1) {
340 #endif
341 WIcon *icon = wapp->app_icon->icon;
342 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
343 int x=0, y=0;
345 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
346 wapp->app_icon->attracted = 1;
347 if (!clip->keep_attracted && !wapp->app_icon->icon->shadowed) {
348 wapp->app_icon->icon->shadowed = 1;
349 wapp->app_icon->icon->force_paint = 1;
350 /* We don't do an wAppIconPaint() here because it's in
351 * wDockAttachIcon(). -Dan
354 wDockAttachIcon(clip, wapp->app_icon, x, y);
355 } else {
356 PlaceIcon(scr, &x, &y);
357 wAppIconMove(wapp->app_icon, x, y);
358 #ifndef STRICTNS
359 wLowerFrame(icon->core);
360 #endif
362 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
363 XMapWindow(dpy, icon->core->window);
366 if (wPreferences.auto_arrange_icons && wapp->app_icon && !wapp->app_icon->attracted) {
367 wArrangeIcons(scr, True);
370 wapp->prev = NULL;
371 wapp->next = scr->wapp_list;
372 if (scr->wapp_list)
373 scr->wapp_list->prev = wapp;
374 scr->wapp_list = wapp;
376 #ifdef WMSOUND
377 wSoundPlay(WMSOUND_APPSTART);
378 #endif
380 #ifdef DEBUG
381 printf("Created application for %x\n", (unsigned)main_window);
382 #endif
383 return wapp;
387 void
388 wApplicationDestroy(WApplication *wapp)
390 Window main_window;
391 WWindow *wwin;
392 WScreen *scr;
393 #ifdef REDUCE_APPICONS
394 unsigned int napps;
395 #endif
397 if (!wapp)
398 return;
400 wapp->refcount--;
401 if (wapp->refcount>0)
402 return;
405 scr = wapp->main_window_desc->screen_ptr;
406 main_window = wapp->main_window;
407 #ifdef REDUCE_APPICONS
408 napps = wAppIconReduceAppCount(wapp);
409 #endif
411 if (wapp == scr->wapp_list) {
412 if (wapp->next)
413 wapp->next->prev = NULL;
414 scr->wapp_list = wapp->next;
415 } else {
416 if (wapp->next)
417 wapp->next->prev = wapp->prev;
418 if (wapp->prev)
419 wapp->prev->next = wapp->next;
422 XDeleteContext(dpy, wapp->main_window, wAppWinContext);
423 wAppMenuDestroy(wapp->menu);
424 if (wapp->app_icon) {
425 if (wapp->app_icon->docked
426 && (!wapp->app_icon->attracted ||
427 wapp->app_icon->dock->keep_attracted)) {
428 #ifdef REDUCE_APPICONS
429 if (napps == 0) {
430 #endif
431 wapp->app_icon->running = 0;
432 /* since we keep it, we don't care if it was attracted or not */
433 wapp->app_icon->attracted = 0;
434 wapp->app_icon->icon->shadowed = 0;
435 wapp->app_icon->main_window = None;
436 wapp->app_icon->pid = 0;
437 wapp->app_icon->icon->owner = NULL;
438 wapp->app_icon->icon->icon_win = None;
439 wapp->app_icon->icon->force_paint = 1;
440 wAppIconPaint(wapp->app_icon);
441 #ifdef REDUCE_APPICONS
443 #endif
444 } else if (wapp->app_icon->docked) {
445 #ifdef REDUCE_APPICONS
446 if (napps == 0) {
447 #endif
448 wapp->app_icon->running = 0;
449 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
450 #ifdef REDUCE_APPICONS
452 #endif
453 } else {
454 #ifdef REDUCE_APPICONS
455 if (napps == 0) {
456 #endif
457 wAppIconDestroy(wapp->app_icon);
458 #ifdef REDUCE_APPICONS
460 #endif
463 wwin = wWindowFor(wapp->main_window_desc->client_win);
465 wWindowDestroy(wapp->main_window_desc);
466 if (wwin) {
467 /* undelete client window context that was deleted in
468 * wWindowDestroy */
469 XSaveContext(dpy, wwin->client_win, wWinContext,
470 (XPointer)&wwin->client_descriptor);
472 free(wapp);
474 #ifdef DEBUG
475 printf("Destroyed application for %x\n", (unsigned)main_window);
476 #endif
477 if (wPreferences.auto_arrange_icons) {
478 wArrangeIcons(scr, True);
481 #ifdef WMSOUND
482 wSoundPlay(WMSOUND_APPEXIT);
483 #endif