1 /* Copyright (C) 1999 Rafal Wierzbicki <rafal@mcss.mcmaster.ca>
2
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 *
18 * TODO:
19 * State Toggles:
20 * Fixed Position
21 * Ignore on Arrange
22 *
23 * no idea what this is:
24 * EXPANDED_SIZE
25 */
26
27 #undef DEBUG
28 static char *cvsident = "$Id: Gnome.c,v 1.5 2009/02/11 23:32:03 sasha Exp $";
29
30 #include <X11/Intrinsic.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xos.h>
34 #include <X11/Xatom.h>
35 #include <X11/Xproto.h>
36 #include <X11/cursorfont.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <signal.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include "../../configure.h"
44 #include "../../include/aftersteplib.h"
45 #include "../../include/afterstep.h"
46 #include "../../include/module.h"
47
48 #include "Gnome.h"
49
50 #ifdef DEBUG
51 #define LOG(s) fprintf (stderr, "%s\n", s)
52 #else
53 #define LOG(s)
54 #endif
55
56 static s_list *window_list; /* single linked list of window id's etc */
57 static int current_desk = 0; /* current workspace */
58 static char **desk_names; /* holds workspace names */
59 static int desk_count = 0; /* number of workspaces */
60 static Bool PAGES = False; /* virtual paging or no */
61 static int area_x = 0; /* area coordinates for virtual paging */
62 static int area_y = 0; /* "" */
63
64
65 ScreenInfo Scr;
66
67 /* inserts a window id into the list
68 * args: list, id
69 */
70 list_item *
s_list_insert(s_list * list,long id)71 s_list_insert (s_list * list, long id)
72 {
73 list_item *item = NULL;
74
75 item = (list_item *) safemalloc (sizeof (list_item));
76
77 if (!item)
78 return NULL;
79
80 if (list->first == NULL)
81 {
82 list->first = item;
83 list->last = item;
84 }
85 else
86 {
87 list->last->next = item;
88 }
89 item->next = NULL;
90 list->last = item;
91 item->id = id;
92 return item;
93 }
94
95 /* removes an item from list by window id
96 * args: list, id
97 */
98 int
s_list_remove_by_data(s_list * list,long id)99 s_list_remove_by_data (s_list * list, long id)
100 {
101 list_item *tmp1;
102
103 tmp1 = s_list_find_by_data (list, id);
104
105 if (tmp1 == NULL)
106 return 0;
107
108 /* this is our only list item */
109 if (tmp1 == list->first && tmp1 == list->last)
110 {
111 free (tmp1);
112 list->first = NULL;
113 list->last = NULL;
114 return 1;
115 }
116 /* the last item */
117 else if (tmp1 == list->last)
118 {
119 list_item *tmp2;
120
121 tmp2 = list->first;
122 while (tmp2)
123 {
124 if (tmp2->next == list->last)
125 break;
126 tmp2 = tmp2->next;
127 }
128 free (tmp1);
129 tmp2->next = NULL;
130 list->last = tmp2;
131 return 1;
132 }
133 /* the first item */
134 else if (tmp1 == list->first)
135 {
136 list->first = tmp1->next;
137 free (tmp1);
138 return 1;
139 }
140 /*somewhere in between */
141 else
142 {
143 list_item *tmp2;
144
145 tmp2 = list->first;
146 while (tmp2)
147 {
148 if (tmp2->next == tmp1)
149 break;
150 tmp2 = tmp2->next;
151 }
152 tmp2->next = tmp1->next;
153 free (tmp1);
154 return 1;
155 }
156 return 0;
157 }
158
159 /* searches for a window id in a list
160 * args: list, id
161 */
162 list_item *
s_list_find_by_data(s_list * list,long id)163 s_list_find_by_data (s_list * list, long id)
164 {
165 list_item *tmp;
166
167 tmp = list->first;
168
169 if (list->first == NULL && list->last == NULL)
170 return NULL;
171
172 while (tmp)
173 {
174 if (tmp->id == id)
175 return tmp;
176 tmp = tmp->next;
177 }
178 return NULL;
179 }
180
181 /* creates a new single linked list */
182 s_list *
s_list_new()183 s_list_new ()
184 {
185 s_list *list;
186
187 list = (s_list *) safemalloc (sizeof (s_list));
188
189 if (!list)
190 return NULL;
191
192 list->first = list->last = NULL;
193 return list;
194 }
195
196 /* destroys a single linked list
197 * args: list
198 */
199 int
s_list_free(s_list * list)200 s_list_free (s_list * list)
201 {
202 list_item *tmp1, *tmp2;
203
204 tmp1 = list->first;
205 while (tmp1)
206 {
207 tmp2 = tmp1->next;
208 free (tmp1);
209 tmp1 = tmp2;
210 }
211 free (list);
212 return 0;
213 }
214
215 /* returns the count of items in a list, skips transient and windowlistskip
216 * windows
217 * args: list
218 */
219 int
s_list_count(s_list * list)220 s_list_count (s_list * list)
221 {
222 list_item *tmp;
223 int count = 0;
224
225 tmp = list->first;
226
227 while (tmp)
228 {
229 if (!(tmp->flags & WINDOWLISTSKIP))
230 if (!(tmp->flags & TRANSIENT))
231 count++;
232 tmp = tmp->next;
233 }
234 return count;
235 }
236
237 /* sets up the properties and the supported protocols list */
238 static void
gnome_compliance_init()239 gnome_compliance_init ()
240 {
241 Atom supported_list[12];
242 int count;
243
244 root_win = RootWindow (dpy, DefaultScreen(dpy));
245
246 /* supporting WM check */
247 _XA_WIN_SUPPORTING_WM_CHECK = XInternAtom (dpy, "_WIN_SUPPORTING_WM_CHECK",
248 False);
249 _XA_WIN_PROTOCOLS = XInternAtom (dpy, "_WIN_PROTOCOLS", False);
250 _XA_WIN_LAYER = XInternAtom (dpy, "_WIN_LAYER", False);
251 _XA_WIN_STATE = XInternAtom (dpy, "_WIN_STATE", False);
252 _XA_WIN_HINTS = XInternAtom (dpy, "_WIN_HINTS", False);
253 _XA_WIN_APP_STATE = XInternAtom (dpy, "_WIN_APP_STATE", False);
254 /*_XA_WIN_EXPANDED_SIZE = XInternAtom(dpy, "_WIN_EXPANDED_SIZE", False);*/
255 _XA_WIN_ICONS = XInternAtom (dpy, "_WIN_ICONS", False);
256 _XA_WIN_WORKSPACE = XInternAtom (dpy, "_WIN_WORKSPACE", False);
257 _XA_WIN_WORKSPACE_COUNT = XInternAtom (dpy, "_WIN_WORKSPACE_COUNT", False);
258 _XA_WIN_WORKSPACE_NAMES = XInternAtom (dpy, "_WIN_WORKSPACE_NAMES", False);
259 _XA_WIN_CLIENT_LIST = XInternAtom (dpy, "_WIN_CLIENT_LIST", False);
260 _XA_WIN_DESKTOP_BUTTON_PROXY = XInternAtom (dpy, "_WIN_DESKTOP_BUTTON_PROXY",
261 False);
262
263 if (PAGES)
264 {
265 _XA_WIN_AREA_COUNT = XInternAtom (dpy, "_WIN_AREA_COUNT", False);
266 _XA_WIN_AREA = XInternAtom (dpy, "_WIN_AREA", False);
267 }
268
269 /* create the GNOME window */
270 gnome_win = XCreateSimpleWindow (dpy, root_win, 0, 0, 5, 5, 0, 0, 0);
271
272 /* supported WM check */
273 XChangeProperty (dpy, root_win, _XA_WIN_SUPPORTING_WM_CHECK,
274 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &gnome_win, 1);
275 XChangeProperty (dpy, gnome_win, _XA_WIN_SUPPORTING_WM_CHECK,
276 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &gnome_win, 1);
277
278 /* supported protocols */
279 count = 0;
280
281 supported_list[count++] = _XA_WIN_LAYER; /* done */
282 supported_list[count++] = _XA_WIN_STATE; /* done */
283 supported_list[count++] = _XA_WIN_HINTS; /* done */
284 supported_list[count++] = _XA_WIN_APP_STATE; /* ???? */
285 /*supported_list[count++] = _XA_WIN_EXPANDED_SIZE; */
286 supported_list[count++] = _XA_WIN_ICONS; /* ???? */
287 supported_list[count++] = _XA_WIN_WORKSPACE; /* done */
288 supported_list[count++] = _XA_WIN_WORKSPACE_COUNT; /* done */
289 supported_list[count++] = _XA_WIN_WORKSPACE_NAMES; /* done */
290 supported_list[count++] = _XA_WIN_CLIENT_LIST; /* done */
291 if (PAGES)
292 {
293 supported_list[count++] = _XA_WIN_AREA_COUNT;
294 supported_list[count++] = _XA_WIN_AREA;
295 }
296
297 XChangeProperty (dpy, root_win, _XA_WIN_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
298 (unsigned char *) supported_list, count);
299
300 }
301
302 /* sets the number of virtual pages per desk */
303 static void
gnome_set_area_count()304 gnome_set_area_count ()
305 {
306 unsigned long val[2];
307
308 val[0] = 2;
309 val[1] = 2;
310 XChangeProperty (dpy, root_win, _XA_WIN_AREA_COUNT, XA_CARDINAL, 32,
311 PropModeReplace, (unsigned char *) &val, 2);
312 }
313
314 /* sets the current visible page */
315 static void
gnome_set_current_area(int x,int y)316 gnome_set_current_area (int x, int y)
317 {
318 unsigned long val[2];
319
320 val[0] = x;
321 val[1] = y;
322 XChangeProperty (dpy, root_win, _XA_WIN_AREA, XA_CARDINAL, 32,
323 PropModeReplace, (unsigned char *) &val, 2);
324 }
325
326 /* sets the current workspace */
327 static void
gnome_set_current_workspace(int current_desk)328 gnome_set_current_workspace (int current_desk)
329 {
330
331 XChangeProperty (dpy, root_win, _XA_WIN_WORKSPACE, XA_CARDINAL, 32,
332 PropModeReplace, (unsigned char *) ¤t_desk, 1);
333 }
334
335 /* sets the number of workspaces */
336 static void
gnome_set_workspace_count(int workspaces)337 gnome_set_workspace_count (int workspaces)
338 {
339
340 XChangeProperty (dpy, root_win, _XA_WIN_WORKSPACE_COUNT, XA_CARDINAL, 32,
341 PropModeReplace, (unsigned char *) &workspaces, 1);
342
343 }
344
345 /* sets up the 'workspace names' property */
346 static void
gnome_set_workspace_names(int count,char ** names)347 gnome_set_workspace_names (int count, char **names)
348 {
349 XTextProperty text;
350
351 if (XStringListToTextProperty (names, count, &text))
352 {
353 XSetTextProperty (dpy, root_win, &text, _XA_WIN_WORKSPACE_NAMES);
354 XFree (text.value);
355 }
356 }
357
358 /* sets the window list property, skips transients and winlistskip windows */
359 static void
gnome_set_client_list(s_list * list)360 gnome_set_client_list (s_list * list)
361 {
362 Window *windows = NULL;
363 int windows_count = 0, count;
364 list_item *tmp;
365
366 windows_count = s_list_count (list);
367
368 if (windows_count != 0)
369 {
370 windows = safemalloc (sizeof (Window) * windows_count);
371
372 if (!windows)
373 {
374 fprintf (stderr, "gnome_set_client_list: malloc failed\n");
375 return;
376 }
377 tmp = list->first;
378 count = 0;
379 while (tmp)
380 {
381 if (!(tmp->flags & WINDOWLISTSKIP))
382 {
383 if (!(tmp->flags & TRANSIENT))
384 windows[count++] = tmp->id;
385 }
386
387 tmp = tmp->next;
388 }
389 XChangeProperty (dpy, root_win, _XA_WIN_CLIENT_LIST, XA_CARDINAL, 32,
390 PropModeReplace, (unsigned char *) windows, windows_count);
391 free (windows);
392 }
393 }
394
395 /* translates AS window flags to GNOME state properties */
396 static void
gnome_set_win_hints(list_item * aswin)397 gnome_set_win_hints (list_item * aswin)
398 {
399 long flags = 0;
400
401 if (aswin->flags & STICKY)
402 flags |= WIN_STATE_STICKY;
403
404 if (aswin->flags & ICONIFIED)
405 flags |= WIN_STATE_MINIMIZED;
406
407 if (aswin->flags & SHADED)
408 flags |= WIN_STATE_SHADED;
409
410 if (!(aswin->flags & STICKY))
411 if (aswin->workspace != current_desk)
412 flags |= WIN_STATE_HID_WORKSPACE;
413
414 if (aswin->flags & TRANSIENT)
415 flags |= WIN_STATE_HID_TRANSIENT;
416
417 XChangeProperty (dpy, (Window) aswin->id, _XA_WIN_WORKSPACE, XA_CARDINAL,
418 32, PropModeReplace, (unsigned char *) &aswin->workspace, 1);
419
420 XChangeProperty (dpy, (Window) aswin->id, _XA_WIN_STATE, XA_CARDINAL,
421 32, PropModeReplace, (unsigned char *) &flags, 1);
422 }
423
424 /* layer change requests are handled here, GNOME -> AS */
425 static void
gnome_handle_win_layer(XClientMessageEvent * event,Window id,int layer)426 gnome_handle_win_layer (XClientMessageEvent * event, Window id, int layer)
427 {
428 int new_layer;
429 list_item *aswin;
430 char as_mesg[50];
431
432
433 if (event)
434 {
435 new_layer = event->data.l[0];
436 aswin = s_list_find_by_data (window_list, (long) event->window);
437 if (!aswin)
438 return;
439 id = aswin->id;
440 }
441 else
442 new_layer = layer;
443
444 /*desktop layers */
445 switch (new_layer)
446 {
447 case WIN_LAYER_DESKTOP:
448 LOG (" WIN_LAYER_DESKTOP");
449 sprintf (as_mesg, "SetLayer -2\n");
450 SendInfo (fd, as_mesg, id);
451 break;
452 case WIN_LAYER_BELOW:
453 LOG (" WIN_LAYER_BELOW");
454 sprintf (as_mesg, "SetLayer -1\n");
455 SendInfo (fd, as_mesg, id);
456 break;
457 case WIN_LAYER_NORMAL:
458 LOG (" WIN_LAYER_NORMAL");
459 sprintf (as_mesg, "SetLayer 0\n");
460 SendInfo (fd, as_mesg, id);
461 break;
462 case WIN_LAYER_ONTOP:
463 LOG (" WIN_LAYER_ONTOP");
464 sprintf (as_mesg, "SetLayer 1\n");
465 SendInfo (fd, as_mesg, id);
466 break;
467 case WIN_LAYER_DOCK:
468 LOG (" WIN_LAYER_DOCK");
469 sprintf (as_mesg, "SetLayer 1\n");
470 SendInfo (fd, as_mesg, id);
471 break;
472 case WIN_LAYER_ABOVE_DOCK:
473 LOG (" WIN_LAYER_ABOVE_DOCK");
474 sprintf (as_mesg, "SetLayer 2\n");
475 SendInfo (fd, as_mesg, id);
476 break;
477 default:
478 fprintf (stderr, "%s: I don't know anything about layer: %d\n", MyName, new_layer);
479 break;
480 }
481 }
482
483 /* hints change requests are handled here, GNOME -> AS */
484 static void
gnome_handle_win_hints(XClientMessageEvent * event,Window id,long flags)485 gnome_handle_win_hints (XClientMessageEvent * event, Window id, long flags)
486 {
487 list_item *aswin;
488 int hints;
489 Bool update = False;
490 unsigned long tmpflags = 0;
491
492 if (event)
493 {
494 hints = event->data.l[1];
495 aswin = s_list_find_by_data (window_list, (long) event->window);
496 }
497 else
498 {
499 hints = flags;
500 aswin = s_list_find_by_data (window_list, id);
501 }
502
503
504 if (!aswin)
505 {
506 LOG ("gnome_handle_win_hints: got an event for an unknown window");
507 return;
508 }
509
510 if (hints & WIN_HINTS_SKIP_FOCUS)
511 {
512 tmpflags |= NOFOCUS;
513 update = True;
514 LOG (" SKIPFOCUS");
515 }
516
517 if (hints & WIN_HINTS_SKIP_WINLIST)
518 {
519 tmpflags |= WINDOWLISTSKIP;
520 update = True;
521 LOG (" SKIPWINLIST");
522 }
523 if (hints & WIN_HINTS_DO_NOT_COVER)
524 {
525 tmpflags |= AVOID_COVER;
526 update = True;
527 LOG (" AVOIDCOVER");
528 }
529 if (hints & WIN_HINTS_SKIP_TASKBAR)
530 {
531 tmpflags |= CIRCULATESKIP;
532 update = True;
533 LOG (" SKIPTASKBAR");
534 }
535 if (hints & WIN_HINTS_GROUP_TRANSIENT)
536 {
537 tmpflags |= TRANSIENT;
538 update = True;
539 LOG (" TRANSIENT");
540 }
541 if (hints & WIN_HINTS_FOCUS_ON_CLICK)
542 LOG (" FOCUSONCLICK ignored");
543
544 update = True;
545 if (update)
546 {
547 char as_msg[50];
548 sprintf (as_msg, "SET_FLAGS %lu\n", tmpflags);
549 SendInfo (fd, as_msg, aswin->id);
550 gnome_set_client_list (window_list);
551 }
552 }
553
554 /* state requests, GNOME -> AS */
555 static void
gnome_handle_win_state(XClientMessageEvent * event,Window id,long mask)556 gnome_handle_win_state (XClientMessageEvent * event, Window id, long mask)
557 {
558 long new_members, change_mask;
559 list_item *aswin;
560
561 if (event)
562 {
563 aswin = s_list_find_by_data (window_list, (long) event->window);
564 change_mask = event->data.l[0];
565 new_members = event->data.l[1];
566 }
567 else
568 {
569 aswin = s_list_find_by_data (window_list, id);
570 new_members = mask;
571 change_mask = 0;
572 }
573 if (!aswin)
574 return;
575
576 /* stick or unstick */
577 if (new_members & WIN_STATE_STICKY)
578 {
579 if (!(aswin->flags & STICKY))
580 {
581 LOG (" STICKY req");
582 SendInfo (fd, "Stick\n", aswin->id);
583 }
584 }
585 else if (change_mask & WIN_STATE_STICKY)
586 {
587 if (aswin->flags & STICKY)
588 {
589 LOG (" UNSTICKY req");
590 SendInfo (fd, "Stick\n", aswin->id);
591 }
592 }
593
594 if ((new_members & WIN_STATE_MAXIMIZED_VERT) &&
595 (new_members & WIN_STATE_MAXIMIZED_HORIZ))
596 {
597 LOG (" MAX req");
598 SendInfo (fd, "Maximize 100% 100%\n", aswin->id);
599 }
600 else
601 {
602 /* maximize verticaly */
603 if (new_members & WIN_STATE_MAXIMIZED_VERT)
604 {
605 LOG (" MAXVERT req");
606 SendInfo (fd, "Maximize 0% 100%\n", aswin->id);
607 }
608
609 /* maximize horizontaly */
610 if (new_members & WIN_STATE_MAXIMIZED_HORIZ)
611 {
612 LOG (" MAXHOR req");
613 SendInfo (fd, "Maximize 100% 0%\n", aswin->id);
614 }
615 }
616 /* shade or unshade */
617 if (new_members & WIN_STATE_SHADED)
618 {
619 if (!(aswin->flags & SHADED))
620 {
621 LOG (" SHADE req");
622 SendInfo (fd, "Shade 1\n", aswin->id);
623 }
624 }
625 else if (change_mask & WIN_STATE_SHADED)
626 {
627 if (aswin->flags & SHADED)
628 SendInfo (fd, "Shade 0\n", aswin->id);
629 }
630
631 if (new_members & WIN_STATE_HIDDEN)
632 {
633 LOG (" HIDDEN req");
634 SendInfo (fd, "Iconify 1\n", aswin->id);
635 }
636 if (new_members & WIN_STATE_MINIMIZED)
637 {
638 LOG (" MINI req");
639 SendInfo (fd, "Iconify 1\n", aswin->id);
640 }
641 /* check if workspace changed, layers, hints and state are handled
642 * elsewhere
643 */
644 if (event)
645 gnome_get_prop_workspace (aswin->id);
646 }
647
648 /* initial app state, get GNOME state from windows that set them */
649 static void
gnome_get_prop_state(Window id)650 gnome_get_prop_state (Window id)
651 {
652 Atom ret_type;
653 int fmt;
654 unsigned long nitems, bytes_after;
655 long flags, *data = 0;
656
657 if (XGetWindowProperty (dpy, id, _XA_WIN_STATE, 0, 1, False,
658 XA_CARDINAL, &ret_type, &fmt, &nitems, &bytes_after,
659 (unsigned char **) &data) == Success && data)
660 {
661 flags = *data;
662 XFree (data);
663 gnome_handle_win_state (NULL, id, flags);
664 }
665
666 }
667
668 /* initial app hints, get GNOME hints from apps that use them */
669 static void
gnome_get_prop_hints(Window id)670 gnome_get_prop_hints (Window id)
671 {
672 Atom ret_type;
673 int fmt;
674 unsigned long nitems;
675 unsigned long bytes_after;
676 long flags, *data = 0;
677 if (XGetWindowProperty (dpy, id, _XA_WIN_HINTS, 0, 1, False,
678 XA_CARDINAL, &ret_type, &fmt, &nitems,
679 &bytes_after,
680 (unsigned char **) &data) == Success && data)
681 {
682 flags = *data;
683 XFree (data);
684 gnome_handle_win_hints (NULL, id, flags);
685 }
686 }
687
688 /* initial app layer, get GNOME layers from apps that use them */
689 static void
gnome_get_prop_layer(Window id)690 gnome_get_prop_layer (Window id)
691 {
692 Atom ret_type;
693 int fmt;
694 unsigned long nitems;
695 unsigned long bytes_after;
696 long val, *data = 0;
697 if (XGetWindowProperty (dpy, id, _XA_WIN_LAYER, 0, 1, False,
698 XA_CARDINAL, &ret_type, &fmt, &nitems,
699 &bytes_after,
700 (unsigned char **) &data) == Success && data)
701 {
702 val = *data;
703 XFree (data);
704 gnome_handle_win_layer (NULL, id, (int) val);
705 }
706
707 }
708
709 /* initial app workspace, get it from the window if set */
710 static void
gnome_get_prop_workspace(Window id)711 gnome_get_prop_workspace (Window id)
712 {
713 Atom ret_type;
714 int fmt;
715 unsigned long nitems;
716 unsigned long bytes_after;
717 long val, *data = 0;
718
719 LOG ("gnome_get_prop_workspace");
720
721 if (XGetWindowProperty (dpy, id, _XA_WIN_WORKSPACE, 0, 1, False,
722 XA_CARDINAL, &ret_type, &fmt, &nitems,
723 &bytes_after,
724 (unsigned char **) &data) == Success && data)
725 {
726 val = *data;
727 XFree (data);
728 if (val != current_desk)
729 {
730 char msg[50];
731 LOG ("ChangeDesk req");
732 sprintf (msg, "WindowsDesk %d\n", (int) val);
733 SendInfo (fd, msg, id);
734 }
735
736 }
737 }
738
739 /* initial hints, check for GNOME hints on a window */
740 static void
gnome_check_client_hints(Window id)741 gnome_check_client_hints (Window id)
742 {
743 /* state */
744 gnome_get_prop_state (id);
745
746 /* hints */
747 gnome_get_prop_hints (id);
748
749 /* layer */
750 gnome_get_prop_layer (id);
751
752 /* workspace */
753 gnome_get_prop_workspace (id);
754 }
755
756 /* signal handler, also called by AS when it wants to kill the module */
757 void
DeadPipe(int sig)758 DeadPipe (int sig)
759 {
760 #ifdef DEBUG_ALLOCS
761 int i;
762 #endif
763 switch (sig)
764 {
765 case SIGSEGV:
766 fprintf (stderr, "Segmentation fault in %s, please send a bug report\n", MyName);
767 exit (-1);
768 case SIGINT:
769 fprintf (stderr, "User abort, exiting\n");
770 exit (-1);
771 case SIGPIPE:
772 fprintf (stderr, "pipe\n");
773 default:
774 break;
775 }
776 #ifdef DEBUG_ALLOCS
777 s_list_free (window_list);
778 for (i = 0; i < desk_count; i++)
779 free (desk_names[i]);
780 free (desk_names);
781 print_unfreed_mem ();
782 #endif
783 exit (0);
784 }
785
786 /* set_as_mask:
787 * set the mask on the pipe
788 */
789
790 static void
set_as_mask(long unsigned mask)791 set_as_mask (long unsigned mask)
792 {
793 char set_mask_mesg[255];
794
795 sprintf (set_mask_mesg, "SET_MASK %lu\n", mask);
796 SendInfo (fd, set_mask_mesg, 0);
797 }
798
799 /* process AS events */
800 static void
process_message(unsigned long type,int elements,unsigned long * body)801 process_message (unsigned long type, int elements, unsigned long *body)
802 {
803 int status = 0;
804
805 switch (type)
806 {
807 case M_CONFIGURE_WINDOW:
808 status = list_configure (body);
809 break;
810 case M_ADD_WINDOW:
811 status = list_add_window (body);
812 break;
813 case M_DESTROY_WINDOW:
814 status = list_destroy_window (body);
815 break;
816 case M_ICONIFY:
817 status = list_iconify (body);
818 break;
819 case M_DEICONIFY:
820 status = list_deiconify (body);
821 break;
822 case M_WINDOW_NAME:
823 status = list_window_name (body);
824 break;
825 case M_ICON_NAME:
826 status = list_icon_name (body);
827 break;
828 case M_END_WINDOWLIST:
829 status = list_end ();
830 break;
831 case M_NEW_PAGE:
832 if (PAGES)
833 status = list_page_change (body);
834 break;
835 case M_NEW_DESK:
836 LOG ("M_NEW_DESK");
837 status = list_desk_change (body);
838 break;
839 case M_TOGGLE_PAGING:
840 break;
841 default:
842 break;
843 }
844 }
845
846 /* list_configure:
847 * pipe configure events
848 */
849
850 int
list_configure(unsigned long * body)851 list_configure (unsigned long *body)
852 {
853 list_item *item;
854
855 if (body[0] == gnome_win)
856 return 0;
857
858 if (body[0] == None)
859 return 0;
860
861 if ((item = s_list_find_by_data (window_list, body[0])) != NULL)
862 {
863 Bool update = False;
864
865 if (item->flags != body[8])
866 {
867 item->flags = body[8];
868 update = True;
869 }
870 if (item->workspace != body[7])
871 {
872 if (!(item->flags & ICONIFIED))
873 {
874 item->workspace = body[7];
875 update = True;
876 }
877 }
878
879 if (update)
880 {
881 gnome_set_win_hints (item);
882 gnome_set_client_list (window_list);
883 return 1;
884 }
885 return 0;
886 }
887 return (list_add_window (body));
888 }
889 /* list_add_window:
890 * pipe add window events
891 */
892
893 int
list_add_window(unsigned long * body)894 list_add_window (unsigned long *body)
895 {
896 list_item *item;
897
898 LOG ("list_add");
899
900 if (body[0] == None)
901 return 0;
902
903 if (s_list_find_by_data (window_list, body[0]))
904 {
905 LOG ("already exists!");
906 return 0;
907 }
908 if (body[0] == gnome_win)
909 return 0;
910
911 item = s_list_insert (window_list, body[0]);
912 item->flags = body[8];
913 item->workspace = body[7];
914 item->area_x = area_x;
915 item->area_y = area_y;
916 gnome_check_client_hints (item->id);
917 gnome_set_win_hints (item);
918 gnome_set_client_list (window_list);
919 return 1;
920 }
921
922 /* list_window_name:
923 * pipe chage of window name events
924 */
925
926 int
list_window_name(unsigned long * body)927 list_window_name (unsigned long *body)
928 {
929 return 0;
930 }
931
932 /* list_icon_name:
933 * pipe change of icon name events
934 */
935
936 int
list_icon_name(unsigned long * body)937 list_icon_name (unsigned long *body)
938 {
939 return 0;
940 }
941
942 /* list_destroy_window:
943 * pipe destroyed windows event
944 */
945
946 int
list_destroy_window(unsigned long * body)947 list_destroy_window (unsigned long *body)
948 {
949 if (s_list_find_by_data (window_list, body[0]))
950 {
951 s_list_remove_by_data (window_list, body[0]);
952 gnome_set_client_list (window_list);
953 return 1;
954 }
955 return 0;
956 }
957
958 /* list_end
959 * end of window list from pipe
960 */
961
962 static int
list_end(void)963 list_end (void)
964 {
965 gnome_set_current_workspace (current_desk);
966 gnome_set_workspace_count (desk_count);
967 gnome_set_workspace_names (desk_count, desk_names);
968 if (PAGES)
969 {
970 gnome_set_area_count ();
971 gnome_set_current_area (0, 0);
972 }
973 gnome_set_client_list (window_list);
974 return 0;
975 }
976
977 /* list_deiconify:
978 * window deiconified from the pipe
979 */
980
981 int
list_deiconify(unsigned long * body)982 list_deiconify (unsigned long *body)
983 {
984 return 0;
985 }
986
987 /* list_iconify:
988 * window iconified from the pipe
989 */
990
991 int
list_iconify(unsigned long * body)992 list_iconify (unsigned long *body)
993 {
994 return 0;
995 }
996
997 /*rafa */
998 int
list_page_change(unsigned long * body)999 list_page_change (unsigned long *body)
1000 {
1001 current_desk = (int) body[2];
1002
1003 if (body[2] != 10000)
1004 {
1005
1006 if (body[0] > 0)
1007 area_x = 1;
1008 else
1009 area_x = 0;
1010
1011 if (body[1] > 0)
1012 area_y = 1;
1013 else
1014 area_y = 0;
1015 gnome_set_current_area (area_x, area_y);
1016 XFlush (dpy);
1017 }
1018 return 0;
1019 }
1020
1021 int
list_desk_change(unsigned long * body)1022 list_desk_change (unsigned long *body)
1023 {
1024 if (body[0] != 10000)
1025 {
1026 current_desk = (unsigned int) body[0];
1027 gnome_set_current_workspace (current_desk);
1028 }
1029 return 0;
1030 }
1031 static int
error_handler(Display * disp,XErrorEvent * event)1032 error_handler (Display * disp, XErrorEvent * event)
1033 {
1034 /* fprintf (stderr, "%s: internal error, error code %d, request code %d, minor code %d\n . Please send a bug report\n", MyName, event->error_code, event->request_code, event->minor_code); */
1035 return 0;
1036 }
1037
1038 static void
event_handler()1039 event_handler ()
1040 {
1041 XEvent Event;
1042 char tmp[255];
1043
1044 while (XPending (dpy))
1045 {
1046 XNextEvent (dpy, &Event);
1047 switch (Event.type)
1048 {
1049 case PropertyNotify:
1050 if (Event.xproperty.window == gnome_win)
1051 {
1052 gnome_check_client_hints (Event.xclient.window);
1053 LOG ("PropNot");
1054 }
1055 break;
1056 case ClientMessage:
1057 /* change workspace request */
1058 if (Event.xclient.message_type == _XA_WIN_WORKSPACE)
1059 {
1060 int desk;
1061 desk = Event.xclient.data.l[0];
1062 sprintf (tmp, "Desk 10000 %d\n", desk);
1063 SendInfo (fd, tmp, None);
1064 }
1065 /* change layer request */
1066 else if (Event.xclient.message_type == _XA_WIN_LAYER)
1067 {
1068 LOG ("_XA_WIN_LAYER request");
1069 gnome_handle_win_layer (&Event.xclient, None, 0);
1070 }
1071 /* state requests */
1072 else if (Event.xclient.message_type == _XA_WIN_STATE)
1073 {
1074 LOG ("_XA_WIN_STATE request");
1075 gnome_handle_win_state (&Event.xclient, None, 0);
1076 }
1077 /* win hints requests */
1078 else if (Event.xclient.message_type == _XA_WIN_HINTS)
1079 {
1080 LOG ("_XA_WIN_HINTS request");
1081 gnome_handle_win_hints (&Event.xclient, None, 0);
1082 }
1083 break;
1084 default:
1085 break;
1086 }
1087 }
1088 }
1089 /******************************************************************************
1090 EndLessLoop - Read and redraw until we get killed, blocking when can't read
1091 ******************************************************************************/
1092 static void
EndLessLoop()1093 EndLessLoop ()
1094 {
1095 fd_set readset;
1096 struct timeval tv;
1097
1098 while (1)
1099 {
1100 FD_ZERO (&readset);
1101 FD_SET (fd[1], &readset);
1102 FD_SET (x_fd, &readset);
1103 tv.tv_sec = 0;
1104 tv.tv_usec = 0;
1105 #ifdef __hpux
1106 if (!select (fd_width, (int *) &readset, NULL, NULL, &tv))
1107 {
1108 XPending (dpy);
1109 FD_ZERO (&readset);
1110 FD_SET (fd[1], &readset);
1111 FD_SET (x_fd, &readset);
1112 select (fd_width, (int *) &readset, NULL, NULL, NULL);
1113 }
1114 #else
1115 if (!select (fd_width, &readset, NULL, NULL, &tv))
1116 {
1117 XPending (dpy);
1118 FD_ZERO (&readset);
1119 FD_SET (fd[1], &readset);
1120 FD_SET (x_fd, &readset);
1121 select (fd_width, &readset, NULL, NULL, NULL);
1122 }
1123 #endif
1124 if (FD_ISSET (x_fd, &readset))
1125 event_handler ();
1126 if (!FD_ISSET (fd[1], &readset))
1127 continue;
1128 read_as_socket ();
1129 }
1130 }
1131
1132 static void
read_as_socket()1133 read_as_socket ()
1134 {
1135 unsigned long header[3], *body;
1136 if (ReadASPacket (fd[1], header, &body) > 0)
1137 {
1138 process_message (header[1], header[2], body);
1139 free (body);
1140 }
1141 }
1142
1143 static void
version(void)1144 version (void)
1145 {
1146 printf ("%s version %s\n%s\n", MyName, VERSION, cvsident);
1147 exit (0);
1148 }
1149
1150 static void
usage(void)1151 usage (void)
1152 {
1153 printf ("Usage:\n"
1154 "%s [-f [config file]] [-v|--version] [-h|--help]\n", MyName);
1155 exit (0);
1156 }
1157
1158 static void
default_config()1159 default_config ()
1160 {
1161 int i;
1162
1163 desk_count = 4;
1164
1165 desk_names = safemalloc (sizeof (char *));
1166
1167 for (i = 0; i < 4; i++)
1168 {
1169 if (i != 0)
1170 desk_names = realloc (desk_names, sizeof (char *) + i * sizeof (char *));
1171 desk_names[i] = safemalloc (10);
1172 sprintf (desk_names[i], "Desktop %i", i);
1173 }
1174 }
1175
1176
1177 static void
parse_config(char * cfgfile)1178 parse_config (char *cfgfile)
1179 {
1180 char *line, *tline, *tmp;
1181 FILE *ptr;
1182 int len;
1183
1184 if ((ptr = fopen (cfgfile, "r")) == NULL)
1185 {
1186 fprintf (stderr, "%s, can\'t open config file %s, using defaults\n", MyName, "file");
1187 default_config ();
1188 return;
1189 }
1190
1191 line = (char *) safemalloc (MAXLINELENGTH);
1192 len = strlen (MyName);
1193
1194
1195 while ((tline = fgets (line, MAXLINELENGTH, ptr)) != NULL)
1196 {
1197 while (isspace (*tline))
1198 tline++;
1199 if ((*tline == '*') && (!mystrncasecmp (tline + 1, MyName, len)))
1200 {
1201 tline += len + 1;
1202 if (!mystrncasecmp (tline, "DeskName", 8))
1203 {
1204 if (desk_count == 0)
1205 desk_names = malloc (sizeof (char *));
1206 else
1207 desk_names = realloc (desk_names,
1208 sizeof (char *) + desk_count * sizeof (char *));
1209 tmp = tline + 8 + 1;
1210 desk_names[desk_count] = (char *) malloc (strlen (tmp) + 1);
1211 strcpy (desk_names[desk_count], tmp);
1212 desk_count++;
1213 }
1214 if (!mystrncasecmp (tline, "Pages", 5))
1215 {
1216 if (atoi (tline + 5) > 0)
1217 {
1218 LOG ("PAGING IS ON");
1219 PAGES = True;
1220 }
1221 }
1222 }
1223 }
1224
1225 if (desk_count == 0)
1226 default_config ();
1227
1228 free (line);
1229 fclose (ptr);
1230 }
1231
1232 int
main(int argc,char ** argv)1233 main (int argc, char **argv)
1234 {
1235 char *temp;
1236 int i;
1237 char *global_config_file = NULL;
1238 char tmp[128];
1239 FILE *fp = NULL;
1240
1241 /* Save our program name - for error messages */
1242 temp = strrchr (argv[0], '/');
1243 MyName = temp ? temp + 1 : argv[0];
1244
1245 for (i = 1; i < argc && *argv[i] == '-'; i++)
1246 {
1247 if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help"))
1248 usage ();
1249 else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version"))
1250 version ();
1251 else if (!strcmp (argv[i], "-w") || !strcmp (argv[i], "--window"))
1252 i++;
1253 else if (!strcmp (argv[i], "-c") || !strcmp (argv[i], "--context"))
1254 i++;
1255 else if (!strcmp (argv[i], "-f") && i + 1 < argc)
1256 global_config_file = argv[++i];
1257 }
1258
1259 /* Dead pipe == dead AfterStep */
1260 signal (SIGPIPE, DeadPipe);
1261 signal (SIGSEGV, DeadPipe);
1262 signal (SIGINT, DeadPipe);
1263
1264 if ((dpy = XOpenDisplay ("")) == NULL)
1265 {
1266 fprintf (stderr, "%s: couldn't open display %s\n",
1267 MyName, XDisplayName (""));
1268 exit (1);
1269 }
1270 set_current_X_display (dpy);
1271 screen = DefaultScreen (dpy);
1272
1273 /* connect to AfterStep */
1274 temp = module_get_socket_property (RootWindow (dpy, screen));
1275 fd[0] = fd[1] = module_connect (temp);
1276 XFree (temp);
1277 if (fd[0] < 0)
1278 {
1279 fprintf (stderr, "%s: unable to establish connection to AfterStep\n", MyName);
1280 exit (1);
1281 }
1282 temp = safemalloc (9 + strlen (MyName) + 1);
1283 sprintf (temp, "SET_NAME %s", MyName);
1284 SendInfo (fd, temp, None);
1285 free (temp);
1286
1287 x_fd = XConnectionNumber (dpy);
1288 fd_width = GetFdWidth ();
1289
1290 XSetErrorHandler (error_handler);
1291
1292 if (global_config_file != NULL)
1293 temp = PutHome (global_config_file);
1294 else
1295 {
1296 memset (tmp, 128, '\0');
1297 sprintf (tmp, "%s/Gnome", AFTER_DIR);
1298 temp = PutHome (tmp);
1299 if ((fp = fopen (temp, "r")) == NULL)
1300 {
1301 sprintf (tmp, "%s/Gnome", AFTER_SHAREDIR);
1302 free (temp);
1303 temp = PutHome (tmp);
1304 }
1305 }
1306
1307 if (fp)
1308 fclose (fp);
1309
1310 parse_config (temp);
1311 free (temp);
1312
1313 gnome_compliance_init ();
1314
1315 window_list = s_list_new ();
1316
1317
1318 set_as_mask ((long unsigned) mask_reg);
1319 SendInfo (fd, "Send_WindowList\n", 0);
1320
1321 XSelectInput (dpy, root_win, PropertyChangeMask | SubstructureNotifyMask);
1322 XSelectInput (dpy, gnome_win, PropertyChangeMask);
1323
1324 EndLessLoop ();
1325 return 0;
1326 }
1327