2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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,
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
36 #include <WINGs/WUtil.h>
40 #include "WindowMaker.h"
50 #include "xmodifier.h"
53 /**** global variables *****/
55 extern WPreferences wPreferences
;
57 extern Time LastTimestamp
;
60 extern Atom _XA_DND_SELECTION
;
66 putdef(char *line
, char *name
, char *value
)
69 wwarning(_("could not define value for %s for cpp"), name
);
79 putidef(char *line
, char *name
, int value
)
82 snprintf(tmp
, sizeof(tmp
), "%i", value
);
97 user
= getpwuid(getuid());
99 wsyserror(_("could not get password entry for UID %i"), getuid());
102 if (!user
->pw_name
) {
105 return user
->pw_name
;
112 MakeCPPArgs(char *path
)
115 char buffer
[MAXLINE
], *buf
, *line
;
119 line
= wmalloc(MAXLINE
);
122 if ((buf
=getenv("HOSTNAME"))!=NULL
) {
124 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
127 putdef(line
, " -DHOST=", buf
);
128 } else if ((buf
=getenv("HOST"))!=NULL
) {
130 wwarning(_("your machine is misconfigured. HOST is set to %s"),
133 putdef(line
, " -DHOST=", buf
);
137 putdef(line
, " -DUSER=", buf
);
138 putidef(line
, " -DUID=", getuid());
139 buf
= XDisplayName(DisplayString(dpy
));
140 putdef(line
, " -DDISPLAY=", buf
);
141 putdef(line
, " -DWM_VERSION=", VERSION
);
143 visual
= DefaultVisual(dpy
, DefaultScreen(dpy
));
144 putidef(line
, " -DVISUAL=", visual
->class);
146 putidef(line
, " -DDEPTH=", DefaultDepth(dpy
, DefaultScreen(dpy
)));
148 putidef(line
, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy
)));
149 putidef(line
, " -DSCR_HEIGHT=",
150 HeightOfScreen(DefaultScreenOfDisplay(dpy
)));
152 /* put the dir where the menu is being read from to the
156 buf
= strchr(tmp
+1, ' ');
160 buf
= strrchr(tmp
, '/');
162 *buf
= 0; /* trunc filename */
163 putdef(line
, " -I", tmp
);
169 /* this should be done just once, but it works this way */
170 strcpy(buffer
, DEF_CONFIG_PATHS
);
171 buf
= strtok(buffer
, ":");
174 char fullpath
[MAXLINE
];
177 strcpy(fullpath
, buf
);
179 char * wgethomedir();
180 /* home is statically allocated. Don't free it! */
181 char *home
= wgethomedir();
183 strcpy(fullpath
, home
);
184 strcat(fullpath
, &(buf
[1]));
187 putdef(line
, " -I", fullpath
);
189 } while ((buf
= strtok(NULL
, ":"))!=NULL
);
205 * Is win2 below win1?
208 isBelow(WWindow
*win1
, WWindow
*win2
)
213 tmp
= win1
->frame
->core
->stacking
->under
;
215 if (tmp
== win2
->frame
->core
)
217 tmp
= tmp
->stacking
->under
;
220 for (i
=win1
->frame
->core
->stacking
->window_level
-1; i
>=0; i
--) {
221 tmp
= win1
->screen_ptr
->stacking_list
[i
];
223 if (tmp
== win2
->frame
->core
)
225 tmp
= tmp
->stacking
->under
;
239 wFetchName(dpy
, win
, winname
)
244 XTextProperty text_prop
;
248 if (XGetWMName(dpy
, win
, &text_prop
)) {
249 if (text_prop
.value
&& text_prop
.nitems
> 0) {
250 if (text_prop
.encoding
== XA_STRING
) {
251 *winname
= wstrdup((char *)text_prop
.value
);
252 XFree(text_prop
.value
);
254 text_prop
.nitems
= strlen((char *)text_prop
.value
);
255 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >=
256 Success
&& num
> 0 && *list
) {
257 XFree(text_prop
.value
);
258 *winname
= wstrdup(*list
);
259 XFreeStringList(list
);
261 *winname
= wstrdup((char *)text_prop
.value
);
262 XFree(text_prop
.value
);
266 /* the title is set, but it was set to none */
267 *winname
= wstrdup("");
271 /* the hint is probably not set */
279 * XGetIconName Wrapper
284 wGetIconName(dpy
, win
, iconname
)
289 XTextProperty text_prop
;
293 if (XGetWMIconName(dpy
, win
, &text_prop
) != 0 && text_prop
.value
294 && text_prop
.nitems
> 0) {
295 if (text_prop
.encoding
== XA_STRING
)
296 *iconname
= (char *)text_prop
.value
;
298 text_prop
.nitems
= strlen((char *)text_prop
.value
);
299 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >=
300 Success
&& num
> 0 && *list
) {
301 XFree(text_prop
.value
);
302 *iconname
= wstrdup(*list
);
303 XFreeStringList(list
);
305 *iconname
= (char *)text_prop
.value
;
319 /* compress all expose events into a single one */
321 if (XCheckMaskEvent(dpy
, ExposureMask
, &event
)) {
322 /* ignore other exposure events for this window */
323 while (XCheckWindowEvent(dpy
, event
.xexpose
.window
, ExposureMask
,
325 /* eat exposes for other windows */
328 event
.xexpose
.count
= 0;
329 XPutBackEvent(dpy
, &event
);
335 SlideWindow(Window win
, int from_x
, int from_y
, int to_x
, int to_y
)
337 time_t time0
= time(NULL
);
338 float dx
, dy
, x
=from_x
, y
=from_y
, sx
, sy
, px
, py
;
341 /* animation parameters */
347 {ICON_SLIDE_DELAY_UF
, ICON_SLIDE_STEPS_UF
, ICON_SLIDE_SLOWDOWN_UF
},
348 {ICON_SLIDE_DELAY_F
, ICON_SLIDE_STEPS_F
, ICON_SLIDE_SLOWDOWN_F
},
349 {ICON_SLIDE_DELAY_M
, ICON_SLIDE_STEPS_M
, ICON_SLIDE_SLOWDOWN_M
},
350 {ICON_SLIDE_DELAY_S
, ICON_SLIDE_STEPS_S
, ICON_SLIDE_SLOWDOWN_S
},
351 {ICON_SLIDE_DELAY_US
, ICON_SLIDE_STEPS_US
, ICON_SLIDE_SLOWDOWN_US
}};
355 dx
= (float)(to_x
-from_x
);
356 dy
= (float)(to_y
-from_y
);
357 sx
= (dx
== 0 ? 0 : fabs(dx
)/dx
);
358 sy
= (dy
== 0 ? 0 : fabs(dy
)/dy
);
360 if (fabs(dx
) > fabs(dy
)) {
365 px
= dx
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
366 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
367 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
368 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
369 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
370 py
= (sx
== 0 ? 0 : px
*dy
/dx
);
372 py
= dy
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
373 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
374 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
375 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
376 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
377 px
= (sy
== 0 ? 0 : py
*dx
/dy
);
380 while (x
!= to_x
|| y
!= to_y
) {
383 if ((px
<0 && (int)x
< to_x
) || (px
>0 && (int)x
> to_x
))
385 if ((py
<0 && (int)y
< to_y
) || (py
>0 && (int)y
> to_y
))
389 px
= px
* (1.0 - 1/(float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
390 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
391 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
392 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
393 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
394 py
= (sx
== 0 ? 0 : px
*dy
/dx
);
396 py
= py
* (1.0 - 1/(float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
397 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
398 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
399 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
400 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
401 px
= (sy
== 0 ? 0 : py
*dx
/dy
);
404 XMoveWindow(dpy
, win
, (int)x
, (int)y
);
406 if (apars
[(int)wPreferences
.icon_slide_speed
].delay
> 0) {
407 wusleep(apars
[(int)wPreferences
.icon_slide_speed
].delay
*1000L);
411 if (time(NULL
) - time0
> MAX_ANIMATION_TIME
)
414 XMoveWindow(dpy
, win
, to_x
, to_y
);
417 /* compress expose events */
423 ShrinkString(WMFont
*font
, char *string
, int width
)
431 if (wPreferences
.multi_byte_text
)
432 return wstrdup(string
);
435 w
= WMWidthOfString(font
, string
, p
);
436 text
= wmalloc(strlen(string
)+8);
437 strcpy(text
, string
);
441 pos
= strchr(text
, ' ');
443 pos
= strchr(text
, ':');
448 w1
= WMWidthOfString(font
, text
, p
);
465 width
-= WMWidthOfString(font
, "...", 3);
470 while (p2
>p1
&& p1
!=t
) {
471 w
= WMWidthOfString(font
, &string
[p
-t
], t
);
475 } else if (w
<width
) {
481 strcat(text
, &string
[p
-p1
]);
488 FindImage(char *paths
, char *file
)
492 tmp
= strrchr(file
, ':');
495 path
= wfindfile(paths
, file
);
499 path
= wfindfile(paths
, file
);
507 timeoutHandler(void *data
)
514 getTextSelection(WScreen
*screen
, Atom selection
)
548 data
= XFetchBuffer(dpy
, &size
, buffer
);
555 unsigned long len
, bytes
;
559 static Atom clipboard
= 0;
562 clipboard
= XInternAtom(dpy
, "CLIPBOARD", False
);
564 XDeleteProperty(dpy
, screen
->info_window
, clipboard
);
566 XConvertSelection(dpy
, selection
, XA_STRING
,
567 clipboard
, screen
->info_window
,
570 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
572 while (!XCheckTypedWindowEvent(dpy
, screen
->info_window
,
573 SelectionNotify
, &ev
) && !timeout
);
576 WMDeleteTimerHandler(timer
);
578 wwarning("selection retrieval timed out");
582 /* nobody owns the selection or the current owner has
583 * nothing to do with what we need */
584 if (ev
.xselection
.property
== None
) {
588 if (XGetWindowProperty(dpy
, screen
->info_window
,
590 False
, XA_STRING
, &rtype
, &bits
, &len
,
591 &bytes
, (unsigned char**)&data
)!=Success
) {
594 if (rtype
!=XA_STRING
|| bits
!=8) {
595 wwarning("invalid data in text selection");
605 getselection(WScreen
*scr
)
609 tmp
= getTextSelection(scr
, XA_PRIMARY
);
611 tmp
= getTextSelection(scr
, XA_CUT_BUFFER0
);
617 getuserinput(WScreen
*scr
, char *line
, int *ptr
)
625 char tbuffer
[BUFSIZE
], pbuffer
[BUFSIZE
];
628 title
= _("Program Arguments");
629 prompt
= _("Enter command arguments:");
639 for (; line
[*ptr
]!=0 && state
!=_DONE
; (*ptr
)++) {
642 if (line
[*ptr
]=='(') {
651 if (j
<= 0 && line
[*ptr
]==',') {
655 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
-begin
, BUFSIZE
));
656 tbuffer
[WMIN(*ptr
-begin
, BUFSIZE
)] = 0;
657 title
= (char*)tbuffer
;
662 } else if (j
<= 0 && line
[*ptr
]==')') {
665 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
-begin
, BUFSIZE
));
666 tbuffer
[WMIN(*ptr
-begin
, BUFSIZE
)] = 0;
667 title
= (char*)tbuffer
;
671 } else if (line
[*ptr
]=='(') {
673 } else if (line
[*ptr
]==')') {
680 if (line
[*ptr
]==')' && j
==0) {
682 if (*ptr
-begin
> 1) {
683 strncpy(pbuffer
, &line
[begin
], WMIN(*ptr
-begin
, BUFSIZE
));
684 pbuffer
[WMIN(*ptr
-begin
, BUFSIZE
)] = 0;
685 prompt
= (char*)pbuffer
;
688 } else if (line
[*ptr
]=='(')
690 else if (line
[*ptr
]==')')
701 if (!wInputDialog(scr
, title
, prompt
, &ret
))
710 get_dnd_selection(WScreen
*scr
)
712 XTextProperty text_ret
;
718 result
=XGetTextProperty(dpy
, scr
->root_win
, &text_ret
, _XA_DND_SELECTION
);
720 if (result
==0 || text_ret
.value
==NULL
|| text_ret
.encoding
==None
721 || text_ret
.format
==0 || text_ret
.nitems
== 0) {
722 wwarning(_("unable to get dropped data from DND drop"));
726 XTextPropertyToStringList(&text_ret
, &list
, &count
);
728 if (!list
|| count
<1) {
729 XFree(text_ret
.value
);
730 wwarning(_("error getting dropped data from DND drop"));
734 flat_string
= wtokenjoin(list
, count
);
736 wwarning(_("out of memory while getting data from DND drop"));
739 XFreeStringList(list
);
740 XFree(text_ret
.value
);
743 #endif /* OFFIX_DND */
751 * state input new-state output
752 * NORMAL % OPTION <nil>
753 * NORMAL \ ESCAPE <nil>
754 * NORMAL etc. NORMAL <input>
755 * ESCAPE any NORMAL <input>
756 * OPTION s NORMAL <selection buffer>
757 * OPTION w NORMAL <selected window id>
758 * OPTION a NORMAL <input text>
759 * OPTION d NORMAL <OffiX DND selection object>
760 * OPTION W NORMAL <current workspace>
761 * OPTION etc. NORMAL %<input>
763 #define TMPBUFSIZE 64
765 ExpandOptions(WScreen
*scr
, char *cmdline
)
767 int ptr
, optr
, state
, len
, olen
;
769 char *selection
=NULL
;
770 char *user_input
=NULL
;
771 #if defined(OFFIX_DND) || defined(XDND)
772 char *dropped_thing
=NULL
;
774 char tmpbuf
[TMPBUFSIZE
];
777 len
= strlen(cmdline
);
781 wwarning(_("out of memory during expansion of \"%s\""));
785 ptr
= 0; /* input line pointer */
786 optr
= 0; /* output line pointer */
791 switch (cmdline
[ptr
]) {
800 out
[optr
++]=cmdline
[ptr
];
805 switch (cmdline
[ptr
]) {
819 out
[optr
++]=cmdline
[ptr
];
825 switch (cmdline
[ptr
]) {
827 if (scr
->focused_window
828 && scr
->focused_window
->flags
.focused
) {
829 snprintf(tmpbuf
, sizeof(tmpbuf
), "0x%x",
830 (unsigned int)scr
->focused_window
->client_win
);
831 slen
= strlen(tmpbuf
);
833 nout
= realloc(out
,olen
);
835 wwarning(_("out of memory during expansion of \"%w\""));
847 snprintf(tmpbuf
, sizeof(tmpbuf
), "0x%x",
848 (unsigned int)scr
->current_workspace
+ 1);
849 slen
= strlen(tmpbuf
);
851 nout
= realloc(out
,olen
);
853 wwarning(_("out of memory during expansion of \"%W\""));
863 user_input
= getuserinput(scr
, cmdline
, &ptr
);
865 slen
= strlen(user_input
);
867 nout
= realloc(out
,olen
);
869 wwarning(_("out of memory during expansion of \"%a\""));
873 strcat(out
,user_input
);
876 /* Not an error, but user has Canceled the dialog box.
877 * This will make the command to not be performed. */
882 #if defined(OFFIX_DND) || defined(XDND)
886 dropped_thing
= wstrdup(scr
->xdestring
);
889 if (!dropped_thing
) {
890 dropped_thing
= get_dnd_selection(scr
);
892 if (!dropped_thing
) {
893 scr
->flags
.dnd_data_convertion_status
= 1;
896 slen
= strlen(dropped_thing
);
898 nout
= realloc(out
,olen
);
900 wwarning(_("out of memory during expansion of \"%d\""));
904 strcat(out
,dropped_thing
);
907 #endif /* OFFIX_DND */
911 selection
= getselection(scr
);
914 wwarning(_("selection not available"));
917 slen
= strlen(selection
);
919 nout
= realloc(out
,olen
);
921 wwarning(_("out of memory during expansion of \"%s\""));
925 strcat(out
,selection
);
931 out
[optr
++]=cmdline
[ptr
];
951 ParseWindowName(WMPropList
*value
, char **winstance
, char **wclass
, char *where
)
955 *winstance
= *wclass
= NULL
;
957 if (!WMIsPLString(value
)) {
958 wwarning(_("bad window name value in %s state info"), where
);
962 name
= WMGetFromPLString(value
);
963 if (!name
|| strlen(name
)==0) {
964 wwarning(_("bad window name value in %s state info"), where
);
968 UnescapeWM_CLASS(name
, winstance
, wclass
);
974 keysymToString(KeySym keysym
, unsigned int state
)
977 char *buf
= wmalloc(20);
982 kev
.send_event
= False
;
983 kev
.window
= DefaultRootWindow(dpy
);
984 kev
.root
= DefaultRootWindow(dpy
);
985 kev
.same_screen
= True
;
986 kev
.subwindow
= kev
.root
;
987 kev
.serial
= 0x12344321;
988 kev
.time
= CurrentTime
;
990 kev
.keycode
= XKeysymToKeycode(dpy
, keysym
);
991 count
= XLookupString(&kev
, buf
, 19, NULL
, NULL
);
1000 GetShortcutString(char *text
)
1002 char *buffer
= NULL
;
1009 tmp
= text
= wstrdup(text
);
1012 while ((k
= strchr(text
, '+'))!=NULL
) {
1016 mod
= wXModifierFromKey(text
);
1018 return wstrdup("bug");
1023 if (strcasecmp(text
, "Meta")==0) {
1024 buffer
= wstrappend(buffer
, "M+");
1025 } else if (strcasecmp(text
, "Alt")==0) {
1026 buffer
= wstrappend(buffer
, "A+");
1027 } else if (strcasecmp(text
, "Shift")==0) {
1028 buffer
= wstrappend(buffer
, "Sh+");
1029 } else if (strcasecmp(text
, "Mod1")==0) {
1030 buffer
= wstrappend(buffer
, "M1+");
1031 } else if (strcasecmp(text
, "Mod2")==0) {
1032 buffer
= wstrappend(buffer
, "M2+");
1033 } else if (strcasecmp(text
, "Mod3")==0) {
1034 buffer
= wstrappend(buffer
, "M3+");
1035 } else if (strcasecmp(text
, "Mod4")==0) {
1036 buffer
= wstrappend(buffer
, "M4+");
1037 } else if (strcasecmp(text
, "Mod5")==0) {
1038 buffer
= wstrappend(buffer
, "M5+");
1039 } else if (strcasecmp(text
, "Control")==0) {
1042 buffer
= wstrappend(buffer
, text
);
1048 buffer
= wstrappend(buffer
, "^");
1050 buffer
= wstrappend(buffer
, text
);
1053 /* ksym = XStringToKeysym(text);
1054 tmp = keysymToString(ksym, modmask);
1056 buffer = wstrappend(buffer, tmp);
1065 EscapeWM_CLASS(char *name
, char *class)
1068 char *ename
= NULL
, *eclass
= NULL
;
1071 if (!name
&& !class)
1076 ename
= wmalloc(l
*2+1);
1078 for (i
=0; i
<l
; i
++) {
1079 if (name
[i
]=='\\') {
1081 } else if (name
[i
]=='.') {
1084 ename
[j
++] = name
[i
];
1090 eclass
= wmalloc(l
*2+1);
1092 for (i
=0; i
<l
; i
++) {
1093 if (class[i
]=='\\') {
1095 } else if (class[i
]=='.') {
1098 eclass
[j
++] = class[i
];
1103 if (ename
&& eclass
) {
1104 int len
= strlen(ename
)+strlen(eclass
)+4;
1106 snprintf(ret
, len
, "%s.%s", ename
, eclass
);
1110 ret
= wstrdup(ename
);
1113 ret
= wstrdup(eclass
);
1122 UnescapeWM_CLASS(char *str
, char **name
, char **class)
1129 *class = wmalloc(j
);
1132 /* separate string in 2 parts */
1134 for (i
= 0; i
< j
; i
++) {
1138 } else if (str
[i
]=='.') {
1144 /* unescape strings */
1145 for (i
=0, k
=0; i
< dot
; i
++) {
1149 (*name
)[k
++] = str
[i
];
1154 for (i
=dot
+1, k
=0; i
<j
; i
++) {
1158 (*class)[k
++] = str
[i
];
1176 SendHelperMessage(WScreen
*scr
, char type
, int workspace
, char *msg
)
1178 unsigned char *buffer
;
1183 if (!scr
->flags
.backimage_helper_launched
) {
1187 len
= (msg
? strlen(msg
) : 0) + (workspace
>=0 ? 4 : 0) + 1 ;
1188 buffer
= wmalloc(len
+5);
1189 snprintf(buf
, len
, "%4i", len
);
1190 memcpy(buffer
, buf
, 4);
1193 if (workspace
>= 0) {
1194 snprintf(buf
, sizeof(buf
), "%4i", workspace
);
1195 memcpy(&buffer
[i
], buf
, 4);
1200 strcpy(&buffer
[i
], msg
);
1202 if (write(scr
->helper_fd
, buffer
, len
+4) < 0) {
1203 wsyserror(_("could not send message to background image helper"));
1210 UpdateDomainFile(WDDomain
*domain
)
1213 char path
[PATH_MAX
];
1214 WMPropList
*shared_dict
, *dict
;
1215 Bool result
, freeDict
= False
;
1217 dict
= domain
->dictionary
;
1218 if (WMIsPLDictionary(domain
->dictionary
)) {
1219 /* retrieve global system dictionary */
1220 snprintf(path
, sizeof(path
), "%s/WindowMaker/%s",
1221 SYSCONFDIR
, domain
->domain_name
);
1222 if (stat(path
, &stbuf
) >= 0) {
1223 shared_dict
= WMReadPropListFromFile(path
);
1225 if (WMIsPLDictionary(shared_dict
)) {
1227 dict
= WMDeepCopyPropList(domain
->dictionary
);
1228 WMSubtractPLDictionaries(dict
, shared_dict
, True
);
1230 WMReleasePropList(shared_dict
);
1235 result
= WMWritePropListToFile(dict
, domain
->path
, True
);
1238 WMReleasePropList(dict
);
1246 StrConcatDot(char *a
, char *b
)
1256 len
= strlen(a
)+strlen(b
)+4;
1259 snprintf(str
, len
, "%s.%s", a
, b
);
1267 static Atom net_wm_pid
= None
;
1270 GetPidForWindow(Window win
)
1274 unsigned long nitems_ret
;
1275 unsigned long bytes_after_ret
;
1279 if (net_wm_pid
== None
) {
1280 net_wm_pid
= XInternAtom(dpy
, "_NET_WM_PID", False
);
1283 if (XGetWindowProperty(dpy
, win
, net_wm_pid
, 0, 1, False
,
1284 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1286 (unsigned char**)&data
)==Success
&& data
) {
1301 GetCommandForPid(int pid
, char ***argv
, int *argc
)
1307 sprintf(buf
, "/proc/%d/cmdline", pid
);
1308 fPtr
= fopen(buf
, "r");
1310 count
= read(fileno(fPtr
), buf
, 1024);
1313 for (i
=0, *argc
=0; i
<count
; i
++) {
1322 *argv
= (char**) wmalloc(sizeof(char*) * (*argc
));
1324 for (i
=0, j
=1; i
<count
; i
++) {
1328 (*argv
)[j
++] = &buf
[i
+1];
1343 getCommandForWindow(Window win
, int elements
)
1345 char **argv
, *command
= NULL
;
1348 if (XGetCommand(dpy
, win
, &argv
, &argc
)) {
1349 if (argc
> 0 && argv
!= NULL
) {
1352 command
= wtokenjoin(argv
, WMIN(argc
, elements
));
1353 if (command
[0] == 0) {
1359 XFreeStringList(argv
);
1367 /* Free result when done */
1369 GetCommandForWindow(Window win
)
1371 return getCommandForWindow(win
, 0);
1375 /* Free result when done */
1377 GetProgramNameForWindow(Window win
)
1379 return getCommandForWindow(win
, 1);