Only build the 'travis' github branch on Travis
[notion/jeffpc.git] / mod_sm / sm_matchwin.c
blob811b1b5ca41c9707f83476941a5da8b653173c0a
1 /*
2 * ion/mod_sm/sm_mathcwin.c
4 * Copyright (c) Tuomo Valkonen 2004-2009.
5 *
6 * Based on the code of the 'sm' module for Ion1 by an unknown contributor.
8 * This is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
14 #include <string.h>
15 #include <unistd.h>
16 #include <time.h>
17 #include <X11/Xatom.h>
19 #include <libmainloop/signal.h>
20 #include <ioncore/common.h>
21 #include <ioncore/global.h>
22 #include <ioncore/exec.h>
23 #include <ioncore/names.h>
24 #include <ioncore/property.h>
26 #include "sm_matchwin.h"
28 #define TIME_OUT 60000
30 static WWinMatch *match_list=NULL;
31 static WTimer *purge_timer=NULL;
34 char *mod_sm_get_window_role(Window window)
36 Atom atom;
37 XTextProperty tp;
39 atom=XInternAtom(ioncore_g.dpy, "WM_WINDOW_ROLE", False);
41 if(XGetTextProperty(ioncore_g.dpy, window, &tp, atom))
43 if(tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
44 return((char *)tp.value);
47 return NULL;
50 Window mod_sm_get_client_leader(Window window)
52 Window client_leader = 0;
53 Atom atom;
54 Atom actual_type;
55 int actual_format;
56 unsigned long nitems;
57 unsigned long bytes_after;
58 unsigned char *prop = NULL;
60 atom=XInternAtom(ioncore_g.dpy, "WM_CLIENT_LEADER", False);
62 if(XGetWindowProperty(ioncore_g.dpy, window, atom,
63 0L, 1L, False, AnyPropertyType, &actual_type,
64 &actual_format, &nitems, &bytes_after,
65 &prop) == Success)
67 if(actual_type == XA_WINDOW && actual_format == 32
68 && nitems == 1 && bytes_after == 0)
69 client_leader=*((Window *)prop);
70 XFree(prop);
72 return client_leader;
75 char *mod_sm_get_client_id(Window window)
77 char *client_id = NULL;
78 Window client_leader;
79 XTextProperty tp;
80 Atom atom;
82 if((client_leader=mod_sm_get_client_leader(window))!=0){
83 atom=XInternAtom(ioncore_g.dpy, "SM_CLIENT_ID", False);
84 if (XGetTextProperty (ioncore_g.dpy, client_leader, &tp, atom))
85 if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
86 client_id = (char *) tp.value;
89 return client_id;
92 char *mod_sm_get_window_cmd(Window window)
94 char **cmd_argv, *command=NULL;
95 int id, i, len=0, cmd_argc=0;
97 if(XGetCommand(ioncore_g.dpy, window, &cmd_argv, &cmd_argc) && (cmd_argc > 0))
99 else if((id=mod_sm_get_client_leader(window)))
100 XGetCommand(ioncore_g.dpy, id, &cmd_argv, &cmd_argc);
102 if(cmd_argc > 0){
103 for(i=0; i < cmd_argc; i++)
104 len+=strlen(cmd_argv[i])+1;
105 command=ALLOC_N(char, len+1);
106 strcpy(command, cmd_argv[0]);
107 for(i=1; i < cmd_argc; i++){
108 strcat(command, " ");
109 strcat(command, cmd_argv[i]);
111 XFreeStringList(cmd_argv);
114 return command;
117 static void free_win_match(WWinMatch *match)
119 UNLINK_ITEM(match_list, match, next, prev);
121 if(match->pholder!=NULL)
122 destroy_obj((Obj*)match->pholder);
124 if(match->client_id)
125 free(match->client_id);
126 if(match->window_role)
127 free(match->window_role);
128 if(match->wclass)
129 free(match->wclass);
130 if(match->wm_name)
131 free(match->wm_name);
132 if(match->wm_cmd)
133 free(match->wm_cmd);
134 free(match);
137 static void mod_sm_purge_matches(WTimer *timer)
139 assert(timer==purge_timer);
140 purge_timer=NULL;
141 destroy_obj((Obj*)timer);
143 #ifdef DEBUG
144 warn("purging remaining matches\n");
145 #endif
146 while(match_list)
147 free_win_match(match_list);
150 void mod_sm_start_purge_timer()
152 if(purge_timer==NULL)
153 purge_timer=create_timer();
154 if(purge_timer!=NULL){
155 timer_set(purge_timer, TIME_OUT,
156 (WTimerHandler*)mod_sm_purge_matches, NULL);
160 void mod_sm_register_win_match(WWinMatch *match)
162 LINK_ITEM(match_list, match, next, prev);
165 bool mod_sm_have_match_list()
167 if(match_list!=NULL)
168 return TRUE;
169 else
170 return FALSE;
173 #define xstreq(a,b) (a && b && (strcmp(a,b)==0))
175 /* Tries to match a window against a list of loaded matches */
177 static WWinMatch *match_cwin(WClientWin *cwin)
179 WWinMatch *match=match_list;
180 int win_match;
181 XClassHint clss;
182 char *client_id=mod_sm_get_client_id(cwin->win);
183 char *window_role=mod_sm_get_window_role(cwin->win);
184 char *wm_cmd=mod_sm_get_window_cmd(cwin->win);
185 char **wm_name=NULL;
186 int n;
188 wm_name=xwindow_get_text_property(cwin->win, XA_WM_NAME, &n);
189 if(n<=0)
190 assert(wm_name==NULL);
192 XGetClassHint(ioncore_g.dpy, cwin->win, &clss);
194 for(; match!=NULL; match=match->next){
196 win_match=0;
198 if(client_id || match->client_id){
199 if(xstreq(match->client_id, client_id)){
200 win_match+=2;
201 if(xstreq(match->window_role, window_role))
202 win_match++;
205 if(win_match<3){
206 if(xstreq(match->wclass, clss.res_class) && xstreq(match->winstance, clss.res_name)){
207 win_match++;
208 if(win_match<3){
209 if(xstreq(match->wm_cmd, wm_cmd))
210 win_match++;
211 if(wm_name!=NULL && *wm_name!=NULL &&
212 xstreq(match->wm_name, *wm_name)){
213 win_match++;
218 if(win_match>2)
219 break;
221 XFree(client_id);
222 XFree(window_role);
223 XFreeStringList(wm_name);
224 free(wm_cmd);
225 return match;
228 /* Returns frame_id of a match. Called from add_clientwin_alt in sm.c */
230 WPHolder *mod_sm_match_cwin_to_saved(WClientWin *cwin)
232 WWinMatch *match=NULL;
233 WPHolder *ph=NULL;
235 if((match=match_cwin(cwin))){
236 ph=match->pholder;
237 match->pholder=NULL;
238 free_win_match(match);
241 return ph;
245 bool mod_sm_add_match(WPHolder *ph, ExtlTab tab)
247 WWinMatch *m=NULL;
249 m=ALLOC(WWinMatch);
250 if(m==NULL)
251 return FALSE;
253 m->client_id=NULL;
254 m->window_role=NULL;
255 m->winstance=NULL;
256 m->wclass=NULL;
257 m->wm_name=NULL;
258 m->wm_cmd=NULL;
260 extl_table_gets_s(tab, "mod_sm_client_id", &(m->client_id));
261 extl_table_gets_s(tab, "mod_sm_window_role", &(m->window_role));
262 extl_table_gets_s(tab, "mod_sm_wclass", &(m->wclass));
263 extl_table_gets_s(tab, "mod_sm_winstance", &(m->winstance));
264 extl_table_gets_s(tab, "mod_sm_wm_name", &(m->wm_name));
265 extl_table_gets_s(tab, "mod_sm_wm_cmd", &(m->wm_cmd));
267 m->pholder=ph;
269 mod_sm_register_win_match(m);
271 return TRUE;
275 void mod_sm_get_configuration(WClientWin *cwin, ExtlTab tab)
277 XClassHint clss;
278 char *client_id=NULL, *window_role=NULL, *wm_cmd=NULL, **wm_name;
279 int n=0;
281 if((client_id=mod_sm_get_client_id(cwin->win))){
282 extl_table_sets_s(tab, "mod_sm_client_id", client_id);
283 XFree(client_id);
287 if((window_role=mod_sm_get_window_role(cwin->win))){
288 extl_table_sets_s(tab, "mod_sm_window_role", window_role);
289 XFree(window_role);
292 if(XGetClassHint(ioncore_g.dpy, cwin->win, &clss) != 0){
293 extl_table_sets_s(tab, "mod_sm_wclass", clss.res_class);
294 extl_table_sets_s(tab, "mod_sm_winstance", clss.res_name);
297 wm_name=xwindow_get_text_property(cwin->win, XA_WM_NAME, &n);
299 if(n>0 && wm_name!=NULL){
300 extl_table_sets_s(tab, "mod_sm_wm_name", *wm_name);
301 XFreeStringList(wm_name);
305 if((wm_cmd=mod_sm_get_window_cmd(cwin->win))){
306 extl_table_sets_s(tab, "mod_sm_wm_cmd", wm_cmd);
307 free(wm_cmd);