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>
39 #include "WindowMaker.h"
49 #include "xmodifier.h"
51 /**** global variables *****/
53 extern WPreferences wPreferences
;
55 extern Time LastTimestamp
;
58 static void putdef(char *line
, char *name
, char *value
)
61 wwarning(_("could not define value for %s for cpp"), name
);
68 static void putidef(char *line
, char *name
, int value
)
71 snprintf(tmp
, sizeof(tmp
), "%i", value
);
76 static char *username()
84 user
= getpwuid(getuid());
86 wsyserror(_("could not get password entry for UID %i"), getuid());
98 char *MakeCPPArgs(char *path
)
101 char buffer
[MAXLINE
], *buf
, *line
;
105 line
= wmalloc(MAXLINE
);
108 if ((buf
= getenv("HOSTNAME")) != NULL
) {
110 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"), buf
);
112 putdef(line
, " -DHOST=", buf
);
113 } else if ((buf
= getenv("HOST")) != NULL
) {
115 wwarning(_("your machine is misconfigured. HOST is set to %s"), buf
);
117 putdef(line
, " -DHOST=", buf
);
121 putdef(line
, " -DUSER=", buf
);
122 putidef(line
, " -DUID=", getuid());
123 buf
= XDisplayName(DisplayString(dpy
));
124 putdef(line
, " -DDISPLAY=", buf
);
125 putdef(line
, " -DWM_VERSION=", VERSION
);
127 visual
= DefaultVisual(dpy
, DefaultScreen(dpy
));
128 putidef(line
, " -DVISUAL=", visual
->class);
130 putidef(line
, " -DDEPTH=", DefaultDepth(dpy
, DefaultScreen(dpy
)));
132 putidef(line
, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy
)));
133 putidef(line
, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy
)));
135 /* put the dir where the menu is being read from to the
139 buf
= strchr(tmp
+ 1, ' ');
143 buf
= strrchr(tmp
, '/');
145 *buf
= 0; /* trunc filename */
146 putdef(line
, " -I", tmp
);
151 /* this should be done just once, but it works this way */
152 strcpy(buffer
, DEF_CONFIG_PATHS
);
153 buf
= strtok(buffer
, ":");
156 char fullpath
[MAXLINE
];
159 strcpy(fullpath
, buf
);
162 /* home is statically allocated. Don't free it! */
163 char *home
= wgethomedir();
165 strcpy(fullpath
, home
);
166 strcat(fullpath
, &(buf
[1]));
169 putdef(line
, " -I", fullpath
);
171 } while ((buf
= strtok(NULL
, ":")) != NULL
);
184 * Is win2 below win1?
186 static Bool
isBelow(WWindow
* win1
, WWindow
* win2
)
191 tmp
= win1
->frame
->core
->stacking
->under
;
193 if (tmp
== win2
->frame
->core
)
195 tmp
= tmp
->stacking
->under
;
198 for (i
= win1
->frame
->core
->stacking
->window_level
- 1; i
>= 0; i
--) {
199 tmp
= win1
->screen_ptr
->stacking_list
[i
];
201 if (tmp
== win2
->frame
->core
)
203 tmp
= tmp
->stacking
->under
;
214 Bool
wFetchName(dpy
, win
, winname
)
219 XTextProperty text_prop
;
223 if (XGetWMName(dpy
, win
, &text_prop
)) {
224 if (text_prop
.value
&& text_prop
.nitems
> 0) {
225 if (text_prop
.encoding
== XA_STRING
) {
226 *winname
= wstrdup((char *)text_prop
.value
);
227 XFree(text_prop
.value
);
229 text_prop
.nitems
= strlen((char *)text_prop
.value
);
230 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >=
231 Success
&& num
> 0 && *list
) {
232 XFree(text_prop
.value
);
233 *winname
= wstrdup(*list
);
234 XFreeStringList(list
);
236 *winname
= wstrdup((char *)text_prop
.value
);
237 XFree(text_prop
.value
);
241 /* the title is set, but it was set to none */
242 *winname
= wstrdup("");
246 /* the hint is probably not set */
254 * XGetIconName Wrapper
258 Bool
wGetIconName(dpy
, win
, iconname
)
263 XTextProperty text_prop
;
267 if (XGetWMIconName(dpy
, win
, &text_prop
) != 0 && text_prop
.value
&& text_prop
.nitems
> 0) {
268 if (text_prop
.encoding
== XA_STRING
)
269 *iconname
= (char *)text_prop
.value
;
271 text_prop
.nitems
= strlen((char *)text_prop
.value
);
272 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >= Success
&& num
> 0 && *list
) {
273 XFree(text_prop
.value
);
274 *iconname
= wstrdup(*list
);
275 XFreeStringList(list
);
277 *iconname
= (char *)text_prop
.value
;
285 static void eatExpose()
289 /* compress all expose events into a single one */
291 if (XCheckMaskEvent(dpy
, ExposureMask
, &event
)) {
292 /* ignore other exposure events for this window */
293 while (XCheckWindowEvent(dpy
, event
.xexpose
.window
, ExposureMask
, &foo
)) ;
294 /* eat exposes for other windows */
297 event
.xexpose
.count
= 0;
298 XPutBackEvent(dpy
, &event
);
302 void SlideWindow(Window win
, int from_x
, int from_y
, int to_x
, int to_y
)
304 time_t time0
= time(NULL
);
305 float dx
, dy
, x
= from_x
, y
= from_y
, sx
, sy
, px
, py
;
306 int dx_is_bigger
= 0;
308 /* animation parameters */
315 ICON_SLIDE_DELAY_UF
, ICON_SLIDE_STEPS_UF
, ICON_SLIDE_SLOWDOWN_UF
}, {
316 ICON_SLIDE_DELAY_F
, ICON_SLIDE_STEPS_F
, ICON_SLIDE_SLOWDOWN_F
}, {
317 ICON_SLIDE_DELAY_M
, ICON_SLIDE_STEPS_M
, ICON_SLIDE_SLOWDOWN_M
}, {
318 ICON_SLIDE_DELAY_S
, ICON_SLIDE_STEPS_S
, ICON_SLIDE_SLOWDOWN_S
}, {
319 ICON_SLIDE_DELAY_US
, ICON_SLIDE_STEPS_US
, ICON_SLIDE_SLOWDOWN_US
}};
321 dx
= (float)(to_x
- from_x
);
322 dy
= (float)(to_y
- from_y
);
323 sx
= (dx
== 0 ? 0 : fabs(dx
) / dx
);
324 sy
= (dy
== 0 ? 0 : fabs(dy
) / dy
);
326 if (fabs(dx
) > fabs(dy
)) {
331 px
= dx
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
332 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
333 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
334 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
335 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
336 py
= (sx
== 0 ? 0 : px
* dy
/ dx
);
338 py
= dy
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
339 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
340 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
341 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
342 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
343 px
= (sy
== 0 ? 0 : py
* dx
/ dy
);
346 while (x
!= to_x
|| y
!= to_y
) {
349 if ((px
< 0 && (int)x
< to_x
) || (px
> 0 && (int)x
> to_x
))
351 if ((py
< 0 && (int)y
< to_y
) || (py
> 0 && (int)y
> to_y
))
355 px
= px
* (1.0 - 1 / (float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
356 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
357 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
358 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
359 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
360 py
= (sx
== 0 ? 0 : px
* dy
/ dx
);
362 py
= py
* (1.0 - 1 / (float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
363 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
364 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
365 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
366 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
367 px
= (sy
== 0 ? 0 : py
* dx
/ dy
);
370 XMoveWindow(dpy
, win
, (int)x
, (int)y
);
372 if (apars
[(int)wPreferences
.icon_slide_speed
].delay
> 0) {
373 wusleep(apars
[(int)wPreferences
.icon_slide_speed
].delay
* 1000L);
377 if (time(NULL
) - time0
> MAX_ANIMATION_TIME
)
380 XMoveWindow(dpy
, win
, to_x
, to_y
);
383 /* compress expose events */
387 char *ShrinkString(WMFont
* font
, char *string
, int width
)
396 w
= WMWidthOfString(font
, string
, p
);
397 text
= wmalloc(strlen(string
) + 8);
398 strcpy(text
, string
);
402 pos
= strchr(text
, ' ');
404 pos
= strchr(text
, ':');
409 w1
= WMWidthOfString(font
, text
, p
);
426 width
-= WMWidthOfString(font
, "...", 3);
431 while (p2
> p1
&& p1
!= t
) {
432 w
= WMWidthOfString(font
, &string
[p
- t
], t
);
435 t
= p1
+ (p2
- p1
) / 2;
436 } else if (w
< width
) {
438 t
= p1
+ (p2
- p1
) / 2;
442 strcat(text
, &string
[p
- p1
]);
447 char *FindImage(char *paths
, char *file
)
451 tmp
= strrchr(file
, ':');
454 path
= wfindfile(paths
, file
);
458 path
= wfindfile(paths
, file
);
464 static void timeoutHandler(void *data
)
469 static char *getTextSelection(WScreen
* screen
, Atom selection
)
503 data
= XFetchBuffer(dpy
, &size
, buffer
);
510 unsigned long len
, bytes
;
514 static Atom clipboard
= 0;
517 clipboard
= XInternAtom(dpy
, "CLIPBOARD", False
);
519 XDeleteProperty(dpy
, screen
->info_window
, clipboard
);
521 XConvertSelection(dpy
, selection
, XA_STRING
, clipboard
, screen
->info_window
, CurrentTime
);
523 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
525 while (!XCheckTypedWindowEvent(dpy
, screen
->info_window
, SelectionNotify
, &ev
) && !timeout
) ;
528 WMDeleteTimerHandler(timer
);
530 wwarning("selection retrieval timed out");
534 /* nobody owns the selection or the current owner has
535 * nothing to do with what we need */
536 if (ev
.xselection
.property
== None
) {
540 if (XGetWindowProperty(dpy
, screen
->info_window
,
542 False
, XA_STRING
, &rtype
, &bits
, &len
,
543 &bytes
, (unsigned char **)&data
) != Success
) {
546 if (rtype
!= XA_STRING
|| bits
!= 8) {
547 wwarning("invalid data in text selection");
556 static char *getselection(WScreen
* scr
)
560 tmp
= getTextSelection(scr
, XA_PRIMARY
);
562 tmp
= getTextSelection(scr
, XA_CUT_BUFFER0
);
566 static char *getuserinput(WScreen
* scr
, char *line
, int *ptr
)
574 char tbuffer
[BUFSIZE
], pbuffer
[BUFSIZE
];
576 title
= _("Program Arguments");
577 prompt
= _("Enter command arguments:");
587 for (; line
[*ptr
] != 0 && state
!= _DONE
; (*ptr
)++) {
590 if (line
[*ptr
] == '(') {
599 if (j
<= 0 && line
[*ptr
] == ',') {
603 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
- begin
, BUFSIZE
));
604 tbuffer
[WMIN(*ptr
- begin
, BUFSIZE
)] = 0;
605 title
= (char *)tbuffer
;
610 } else if (j
<= 0 && line
[*ptr
] == ')') {
613 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
- begin
, BUFSIZE
));
614 tbuffer
[WMIN(*ptr
- begin
, BUFSIZE
)] = 0;
615 title
= (char *)tbuffer
;
619 } else if (line
[*ptr
] == '(') {
621 } else if (line
[*ptr
] == ')') {
628 if (line
[*ptr
] == ')' && j
== 0) {
630 if (*ptr
- begin
> 1) {
631 strncpy(pbuffer
, &line
[begin
], WMIN(*ptr
- begin
, BUFSIZE
));
632 pbuffer
[WMIN(*ptr
- begin
, BUFSIZE
)] = 0;
633 prompt
= (char *)pbuffer
;
636 } else if (line
[*ptr
] == '(')
638 else if (line
[*ptr
] == ')')
649 if (!wInputDialog(scr
, title
, prompt
, &ret
))
660 * state input new-state output
661 * NORMAL % OPTION <nil>
662 * NORMAL \ ESCAPE <nil>
663 * NORMAL etc. NORMAL <input>
664 * ESCAPE any NORMAL <input>
665 * OPTION s NORMAL <selection buffer>
666 * OPTION w NORMAL <selected window id>
667 * OPTION a NORMAL <input text>
668 * OPTION d NORMAL <OffiX DND selection object>
669 * OPTION W NORMAL <current workspace>
670 * OPTION etc. NORMAL %<input>
672 #define TMPBUFSIZE 64
673 char *ExpandOptions(WScreen
* scr
, char *cmdline
)
675 int ptr
, optr
, state
, len
, olen
;
677 char *selection
= NULL
;
678 char *user_input
= NULL
;
680 char *dropped_thing
= NULL
;
682 char tmpbuf
[TMPBUFSIZE
];
685 len
= strlen(cmdline
);
689 wwarning(_("out of memory during expansion of \"%s\""));
693 ptr
= 0; /* input line pointer */
694 optr
= 0; /* output line pointer */
699 switch (cmdline
[ptr
]) {
708 out
[optr
++] = cmdline
[ptr
];
713 switch (cmdline
[ptr
]) {
727 out
[optr
++] = cmdline
[ptr
];
733 switch (cmdline
[ptr
]) {
735 if (scr
->focused_window
&& scr
->focused_window
->flags
.focused
) {
736 snprintf(tmpbuf
, sizeof(tmpbuf
), "0x%x",
737 (unsigned int)scr
->focused_window
->client_win
);
738 slen
= strlen(tmpbuf
);
740 nout
= realloc(out
, olen
);
742 wwarning(_("out of memory during expansion of \"%w\""));
754 snprintf(tmpbuf
, sizeof(tmpbuf
), "0x%x", (unsigned int)scr
->current_workspace
+ 1);
755 slen
= strlen(tmpbuf
);
757 nout
= realloc(out
, olen
);
759 wwarning(_("out of memory during expansion of \"%W\""));
769 user_input
= getuserinput(scr
, cmdline
, &ptr
);
771 slen
= strlen(user_input
);
773 nout
= realloc(out
, olen
);
775 wwarning(_("out of memory during expansion of \"%a\""));
779 strcat(out
, user_input
);
782 /* Not an error, but user has Canceled the dialog box.
783 * This will make the command to not be performed. */
790 if (scr
->xdestring
) {
791 dropped_thing
= wstrdup(scr
->xdestring
);
793 if (!dropped_thing
) {
794 dropped_thing
= get_dnd_selection(scr
);
796 if (!dropped_thing
) {
797 scr
->flags
.dnd_data_convertion_status
= 1;
800 slen
= strlen(dropped_thing
);
802 nout
= realloc(out
, olen
);
804 wwarning(_("out of memory during expansion of \"%d\""));
808 strcat(out
, dropped_thing
);
815 selection
= getselection(scr
);
818 wwarning(_("selection not available"));
821 slen
= strlen(selection
);
823 nout
= realloc(out
, olen
);
825 wwarning(_("out of memory during expansion of \"%s\""));
829 strcat(out
, selection
);
835 out
[optr
++] = cmdline
[ptr
];
853 void ParseWindowName(WMPropList
* value
, char **winstance
, char **wclass
, char *where
)
857 *winstance
= *wclass
= NULL
;
859 if (!WMIsPLString(value
)) {
860 wwarning(_("bad window name value in %s state info"), where
);
864 name
= WMGetFromPLString(value
);
865 if (!name
|| strlen(name
) == 0) {
866 wwarning(_("bad window name value in %s state info"), where
);
870 UnescapeWM_CLASS(name
, winstance
, wclass
);
874 static char *keysymToString(KeySym keysym
, unsigned int state
)
877 char *buf
= wmalloc(20);
882 kev
.send_event
= False
;
883 kev
.window
= DefaultRootWindow(dpy
);
884 kev
.root
= DefaultRootWindow(dpy
);
885 kev
.same_screen
= True
;
886 kev
.subwindow
= kev
.root
;
887 kev
.serial
= 0x12344321;
888 kev
.time
= CurrentTime
;
890 kev
.keycode
= XKeysymToKeycode(dpy
, keysym
);
891 count
= XLookupString(&kev
, buf
, 19, NULL
, NULL
);
898 char *GetShortcutString(char *text
)
907 tmp
= text
= wstrdup(text
);
910 while ((k
= strchr(text
, '+')) != NULL
) {
914 mod
= wXModifierFromKey(text
);
916 return wstrdup("bug");
921 if (strcasecmp(text
, "Meta") == 0) {
922 buffer
= wstrappend(buffer
, "M+");
923 } else if (strcasecmp(text
, "Alt") == 0) {
924 buffer
= wstrappend(buffer
, "A+");
925 } else if (strcasecmp(text
, "Shift") == 0) {
926 buffer
= wstrappend(buffer
, "Sh+");
927 } else if (strcasecmp(text
, "Mod1") == 0) {
928 buffer
= wstrappend(buffer
, "M1+");
929 } else if (strcasecmp(text
, "Mod2") == 0) {
930 buffer
= wstrappend(buffer
, "M2+");
931 } else if (strcasecmp(text
, "Mod3") == 0) {
932 buffer
= wstrappend(buffer
, "M3+");
933 } else if (strcasecmp(text
, "Mod4") == 0) {
934 buffer
= wstrappend(buffer
, "M4+");
935 } else if (strcasecmp(text
, "Mod5") == 0) {
936 buffer
= wstrappend(buffer
, "M5+");
937 } else if (strcasecmp(text
, "Control") == 0) {
940 buffer
= wstrappend(buffer
, text
);
946 buffer
= wstrappend(buffer
, "^");
948 buffer
= wstrappend(buffer
, text
);
951 /* ksym = XStringToKeysym(text);
952 tmp = keysymToString(ksym, modmask);
954 buffer = wstrappend(buffer, tmp);
961 char *EscapeWM_CLASS(char *name
, char *class)
964 char *ename
= NULL
, *eclass
= NULL
;
972 ename
= wmalloc(l
* 2 + 1);
974 for (i
= 0; i
< l
; i
++) {
975 if (name
[i
] == '\\') {
977 } else if (name
[i
] == '.') {
980 ename
[j
++] = name
[i
];
986 eclass
= wmalloc(l
* 2 + 1);
988 for (i
= 0; i
< l
; i
++) {
989 if (class[i
] == '\\') {
991 } else if (class[i
] == '.') {
994 eclass
[j
++] = class[i
];
999 if (ename
&& eclass
) {
1000 int len
= strlen(ename
) + strlen(eclass
) + 4;
1002 snprintf(ret
, len
, "%s.%s", ename
, eclass
);
1006 ret
= wstrdup(ename
);
1009 ret
= wstrdup(eclass
);
1016 void UnescapeWM_CLASS(char *str
, char **name
, char **class)
1023 *class = wmalloc(j
);
1026 /* separate string in 2 parts */
1028 for (i
= 0; i
< j
; i
++) {
1029 if (str
[i
] == '\\') {
1032 } else if (str
[i
] == '.') {
1038 /* unescape strings */
1039 for (i
= 0, k
= 0; i
< dot
; i
++) {
1040 if (str
[i
] == '\\') {
1043 (*name
)[k
++] = str
[i
];
1048 for (i
= dot
+ 1, k
= 0; i
< j
; i
++) {
1049 if (str
[i
] == '\\') {
1052 (*class)[k
++] = str
[i
];
1067 void SendHelperMessage(WScreen
* scr
, char type
, int workspace
, char *msg
)
1074 if (!scr
->flags
.backimage_helper_launched
) {
1078 len
= (msg
? strlen(msg
) : 0) + (workspace
>= 0 ? 4 : 0) + 1;
1079 buffer
= wmalloc(len
+ 5);
1080 snprintf(buf
, sizeof(buf
), "%4i", len
);
1081 memcpy(buffer
, buf
, 4);
1084 if (workspace
>= 0) {
1085 snprintf(buf
, sizeof(buf
), "%4i", workspace
);
1086 memcpy(&buffer
[i
], buf
, 4);
1091 strcpy(&buffer
[i
], msg
);
1093 if (write(scr
->helper_fd
, buffer
, len
+ 4) < 0) {
1094 wsyserror(_("could not send message to background image helper"));
1099 Bool
UpdateDomainFile(WDDomain
* domain
)
1102 char path
[PATH_MAX
];
1103 WMPropList
*shared_dict
, *dict
;
1104 Bool result
, freeDict
= False
;
1106 dict
= domain
->dictionary
;
1107 if (WMIsPLDictionary(domain
->dictionary
)) {
1108 /* retrieve global system dictionary */
1109 snprintf(path
, sizeof(path
), "%s/WindowMaker/%s", SYSCONFDIR
, domain
->domain_name
);
1110 if (stat(path
, &stbuf
) >= 0) {
1111 shared_dict
= WMReadPropListFromFile(path
);
1113 if (WMIsPLDictionary(shared_dict
)) {
1115 dict
= WMDeepCopyPropList(domain
->dictionary
);
1116 WMSubtractPLDictionaries(dict
, shared_dict
, True
);
1118 WMReleasePropList(shared_dict
);
1123 result
= WMWritePropListToFile(dict
, domain
->path
, True
);
1126 WMReleasePropList(dict
);
1132 char *StrConcatDot(char *a
, char *b
)
1142 len
= strlen(a
) + strlen(b
) + 4;
1145 snprintf(str
, len
, "%s.%s", a
, b
);
1150 #define MAX_CMD_SIZE 4096
1152 Bool
GetCommandForPid(int pid
, char ***argv
, int *argc
)
1154 static char buf
[MAX_CMD_SIZE
];
1159 sprintf(buf
, "/proc/%d/cmdline", pid
);
1160 fPtr
= fopen(buf
, "r");
1162 count
= read(fileno(fPtr
), buf
, MAX_CMD_SIZE
);
1165 for (i
= 0, *argc
= 0; i
< count
; i
++) {
1174 *argv
= (char **)wmalloc(sizeof(char *) * (*argc
));
1176 for (i
= 0, j
= 1; i
< count
; i
++) {
1179 if (i
< count
- 1) {
1180 (*argv
)[j
++] = &buf
[i
+ 1];
1195 static char *getCommandForWindow(Window win
, int elements
)
1197 char **argv
, *command
= NULL
;
1200 if (XGetCommand(dpy
, win
, &argv
, &argc
)) {
1201 if (argc
> 0 && argv
!= NULL
) {
1204 command
= wtokenjoin(argv
, WMIN(argc
, elements
));
1205 if (command
[0] == 0) {
1211 XFreeStringList(argv
);
1218 /* Free result when done */
1219 char *GetCommandForWindow(Window win
)
1221 return getCommandForWindow(win
, 0);
1224 /* Free result when done */
1225 char *GetProgramNameForWindow(Window win
)
1227 return getCommandForWindow(win
, 1);