1 /* -*-c-*- */
2
3 /* This module, and the entire NoClutter program, and the concept for
4 * interfacing this module to the Window Manager, are all original work
5 * by Robert Nation and Nobutaka Suzuki <nobuta-s@is.aist-nara.ac.jp>
6 *
7 * Copyright 1994, Robert Nation and Nobutaka Suzuki.
8 * No guarantees or warantees or anything
9 * are provided or implied in any way whatsoever. Use this program at your
10 * own risk. Permission to use this program for any purpose is given,
11 * as long as the copyright is kept intact. */
12
13 /* This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see: <http://www.gnu.org/licenses/>
25 */
26
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <sys/wait.h>
33 #include "libs/ftime.h"
34
35 #if HAVE_SYS_SELECT_H
36 #include <sys/select.h>
37 #endif
38
39 #include <unistd.h>
40 #include <ctype.h>
41
42 #include "libs/fvwm_x11.h"
43 #include "libs/fvwmlib.h"
44 #include "libs/FShape.h"
45 #include "libs/FEvent.h"
46 #include "libs/Module.h"
47 #include "libs/Colorset.h"
48 #include "libs/fvwmsignal.h"
49 #include "libs/Flocale.h"
50 #include "libs/Parse.h"
51 #include "libs/FRenderInit.h"
52 #include "libs/Graphics.h"
53 #include "libs/System.h"
54 #include "libs/Target.h"
55 #include "libs/XError.h"
56
57 #include "FvwmIdent.h"
58
59 static RETSIGTYPE TerminateHandler(int);
60
61 static ModuleArgs *module;
62 static fd_set_size_t fd_width;
63 static int fd[2];
64
65 static Display *dpy; /* which display are we talking to */
66 static Window Root;
67 static GC gc;
68
69 static FlocaleFont *Ffont;
70 static FlocaleWinString *FwinString;
71
72 static int screen;
73 static int x_fd;
74
75 static char *yes = "Yes";
76 static char *no = "No";
77 static char *mname;
78
79 /* default colorset to use, set to -1 when explicitly setting colors */
80 static int colorset = 0;
81
82 static char *BackColor = "white";
83 static char *ForeColor = "black";
84 static char *font_string = NULL;
85
86 static Pixel fore_pix;
87 static Pixel back_pix;
88 static Window main_win;
89 static Bool UsePixmapDrawing = False; /* if True draw everything in a pixmap
90 * and set the window background. Use
91 * this with Xft */
92 static int main_width;
93 static int main_height;
94
95 static EventMask mw_events =
96 ExposureMask | ButtonPressMask | KeyPressMask |
97 ButtonReleaseMask | KeyReleaseMask | StructureNotifyMask;
98
99 static Atom wm_del_win;
100
101 static struct target_struct target;
102 static int found=0;
103
104 static int ListSize=0;
105
106 static struct Item* itemlistRoot = NULL;
107 static int max_col1, max_col2;
108 static char id[15], desktop[21], swidth[12], sheight[12], borderw[21];
109 static char geometry[30], mymin_aspect[24], max_aspect[24], layer[21];
110 static char ewmh_init_state[512];
111
112 /* FIXME: default layer should be received from fvwm */
113 #define default_layer DEFAULT_DEFAULT_LAYER
114 static int minimal_layer = default_layer;
115 static int my_layer = default_layer;
116
117 /*
118 *
119 * Procedure:
120 * main - start of module
121 *
122 */
main(int argc,char ** argv)123 int main(int argc, char **argv)
124 {
125 char *display_name = NULL;
126 char *tline;
127
128 FlocaleInit(LC_CTYPE, "", "", "FvwmIdent");
129
130 module = ParseModuleArgs(argc,argv,0); /* no alias */
131 if (module == NULL)
132 {
133 fvwm_debug(__func__,
134 "FvwmIdent Version %s should only be executed"
135 " by fvwm!\n", VERSION);
136 exit(1);
137 }
138
139 xasprintf(&mname, "*%s", module->name);
140
141 #ifdef HAVE_SIGACTION
142 {
143 struct sigaction sigact;
144
145 sigemptyset(&sigact.sa_mask);
146 sigaddset(&sigact.sa_mask, SIGPIPE);
147 sigaddset(&sigact.sa_mask, SIGTERM);
148 sigaddset(&sigact.sa_mask, SIGQUIT);
149 sigaddset(&sigact.sa_mask, SIGINT);
150 sigaddset(&sigact.sa_mask, SIGHUP);
151 # ifdef SA_INTERRUPT
152 sigact.sa_flags = SA_INTERRUPT;
153 # else
154 sigact.sa_flags = 0;
155 # endif
156 sigact.sa_handler = TerminateHandler;
157
158 sigaction(SIGPIPE, &sigact, NULL);
159 sigaction(SIGTERM, &sigact, NULL);
160 sigaction(SIGQUIT, &sigact, NULL);
161 sigaction(SIGINT, &sigact, NULL);
162 sigaction(SIGHUP, &sigact, NULL);
163 }
164 #else
165 /* We don't have sigaction(), so fall back to less robust methods. */
166 #ifdef USE_BSD_SIGNALS
167 fvwmSetSignalMask( sigmask(SIGPIPE) |
168 sigmask(SIGTERM) |
169 sigmask(SIGQUIT) |
170 sigmask(SIGINT) |
171 sigmask(SIGHUP) );
172 #endif
173 signal(SIGPIPE, TerminateHandler);
174 signal(SIGTERM, TerminateHandler);
175 signal(SIGQUIT, TerminateHandler);
176 signal(SIGINT, TerminateHandler);
177 signal(SIGHUP, TerminateHandler);
178 #ifdef HAVE_SIGINTERRUPT
179 siginterrupt(SIGPIPE, 1);
180 siginterrupt(SIGTERM, 1);
181 siginterrupt(SIGQUIT, 1);
182 siginterrupt(SIGINT, 1);
183 siginterrupt(SIGHUP, 1);
184 #endif
185 #endif
186
187 fd[0] = module->to_fvwm;
188 fd[1] = module->from_fvwm;
189
190 /* Open the Display */
191 if (!(dpy = XOpenDisplay(display_name)))
192 {
193 fvwm_debug(__func__, "%s: can't open display %s",
194 module->name,
195 XDisplayName(display_name));
196 exit (1);
197 }
198 x_fd = XConnectionNumber(dpy);
199 screen= DefaultScreen(dpy);
200 Root = RootWindow(dpy, screen);
201 XSetErrorHandler(ErrorHandler);
202
203 flib_init_graphics(dpy);
204 FlocaleAllocateWinString(&FwinString);
205
206 SetMessageMask(fd, M_CONFIGURE_WINDOW | M_WINDOW_NAME | M_ICON_NAME
207 | M_RES_CLASS | M_RES_NAME | M_END_WINDOWLIST |
208 M_CONFIG_INFO | M_END_CONFIG_INFO | M_SENDCONFIG);
209 SetMessageMask(fd, MX_PROPERTY_CHANGE);
210 /* scan config file for set-up parameters */
211 /* Colors and fonts */
212
213 InitGetConfigLine(fd, mname);
214 GetConfigLine(fd,&tline);
215
216 while (tline != (char *)0)
217 {
218 if (strlen(tline) <= 1)
219 {
220 continue;
221 }
222 if (strncasecmp(tline, mname, module->namelen+1) == 0)
223 {
224 tline += (module->namelen +1);
225 if (strncasecmp(tline, "Font", 4) == 0)
226 {
227 CopyStringWithQuotes(&font_string, &tline[4]);
228 }
229 else if (strncasecmp(tline, "Fore", 4) == 0)
230 {
231 CopyString(&ForeColor, &tline[4]);
232 colorset = -1;
233 }
234 else if (strncasecmp(tline, "Back", 4) == 0)
235 {
236 CopyString(&BackColor, &tline[4]);
237 colorset = -1;
238 }
239 else if (strncasecmp(tline, "Colorset", 8) == 0)
240 {
241 sscanf(&tline[8], "%d", &colorset);
242 AllocColorset(colorset);
243 }
244 else if (strncasecmp(tline, "MinimalLayer", 12) == 0)
245 {
246 char *layer_str = PeekToken(&tline[12], NULL);
247 if (layer_str == NULL)
248 {
249 minimal_layer = default_layer;
250 }
251 else if (sscanf(
252 layer_str, "%d", &minimal_layer) != 1)
253 {
254 if (strncasecmp(
255 layer_str, "none", 4) == 0)
256 {
257 minimal_layer = -1;
258 }
259 else
260 {
261 minimal_layer = default_layer;
262 }
263 }
264 }
265 }
266 else if (strncasecmp(tline, "Colorset", 8) == 0)
267 {
268 LoadColorset(&tline[8]);
269 }
270 GetConfigLine(fd, &tline);
271 }
272
273 if(module->window == 0)
274 {
275 fvwmlib_get_target_window(
276 dpy, screen, module->name, &(module->window), True);
277 }
278
279 fd_width = GetFdWidth();
280
281 /* Create a list of all windows */
282 /* Request a list of all windows,
283 * wait for ConfigureWindow packets */
284 SendText(fd, "Send_WindowList", 0);
285
286 /* tell fvwm we're running */
287 SendFinishedStartupNotification(fd);
288 if (module->window == Root)
289 {
290 exit(0);
291 }
292
293 Loop(fd);
294 return 0;
295 }
296
297 /*
298 *
299 * Read the entire window list from fvwm
300 *
301 */
Loop(int * fd)302 void Loop(int *fd)
303 {
304 while (1)
305 {
306 FvwmPacket* packet = ReadFvwmPacket(fd[1]);
307 if ( packet == NULL )
308 {
309 exit(0);
310 }
311 else
312 {
313 process_message( packet->type, packet->body );
314 }
315 }
316 }
317
318
319 /*
320 *
321 * Process window list messages
322 *
323 */
process_message(unsigned long type,unsigned long * body)324 void process_message(unsigned long type,unsigned long *body)
325 {
326 switch(type)
327 {
328 /* should turn off this packet but it comes after config_list
329 * so have to accept at least one */
330 case M_CONFIGURE_WINDOW:
331 list_configure(body);
332 break;
333 case M_WINDOW_NAME:
334 list_window_name(body);
335 break;
336 case M_ICON_NAME:
337 list_icon_name(body);
338 break;
339 case M_RES_CLASS:
340 list_class(body);
341 break;
342 case M_RES_NAME:
343 list_res_name(body);
344 break;
345 case M_END_WINDOWLIST:
346 list_end();
347 break;
348 default:
349 break;
350 }
351 }
352
353 /*
354 *
355 * Procedure:
356 * SIGPIPE handler - SIGPIPE means fvwm is dying
357 *
358 */
359 static RETSIGTYPE
TerminateHandler(int sig)360 TerminateHandler(int sig)
361 {
362 fvwmSetTerminate(sig);
363 SIGNAL_RETURN;
364 }
365
366 /*
367 *
368 * Got window configuration info - if its our window, save data
369 *
370 */
list_configure(unsigned long * body)371 void list_configure(unsigned long *body)
372 {
373 struct ConfigWinPacket *cfgpacket = (void *) body;
374
375 if (
376 (module->window == cfgpacket->frame)||
377 (module->window == cfgpacket->w) ||
378 ((cfgpacket->icon_w != 0)&&
379 (module->window == cfgpacket->icon_w)) ||
380 ((cfgpacket->icon_pixmap_w)&&
381 (module->window == cfgpacket->icon_pixmap_w)))
382 {
383 module->window = cfgpacket->frame;
384 target.id = cfgpacket->w;
385
386 target.monitor_id = cfgpacket->monitor_id;
387 target.monitor = fxstrdup("unknown");
388 {
389 free(target.monitor);
390 target.monitor = fxstrdup(
391 monitor_by_output((int)target.monitor_id)->si->name);
392 }
393 target.frame = cfgpacket->frame;
394 target.frame_x = cfgpacket->frame_x;
395 target.frame_y = cfgpacket->frame_y;
396 target.frame_w = cfgpacket->frame_width;
397 target.frame_h = cfgpacket->frame_height;
398 target.desktop = cfgpacket->desk;
399 target.layer = cfgpacket->layer;
400 memcpy(&target.flags,
401 &(cfgpacket->flags), sizeof(cfgpacket->flags));
402 target.title_h = cfgpacket->title_height;
403 target.title_dir = GET_TITLE_DIR(cfgpacket);
404 target.border_w = cfgpacket->border_width;
405 target.base_w = cfgpacket->hints_base_width;
406 target.base_h = cfgpacket->hints_base_height;
407 target.width_inc = cfgpacket->orig_hints_width_inc;
408 target.height_inc = cfgpacket->orig_hints_height_inc;
409 target.gravity = cfgpacket->hints_win_gravity;
410 target.ewmh_hint_layer = cfgpacket->ewmh_hint_layer;
411 target.ewmh_hint_desktop = cfgpacket->ewmh_hint_desktop;
412 target.ewmh_window_type = cfgpacket->ewmh_window_type;
413 found = 1;
414
415 my_layer = (int)target.layer;
416 if (my_layer < minimal_layer)
417 {
418 my_layer = minimal_layer;
419 }
420 }
421 }
422
423 /*
424 *
425 * Capture Window name info
426 *
427 */
list_window_name(unsigned long * body)428 void list_window_name(unsigned long *body)
429 {
430 if (
431 (module->window == (Window)body[1])||
432 (module->window == (Window)body[0]))
433 {
434 strncpy(target.name,(char *)&body[3],255);
435 }
436 }
437
438 /*
439 *
440 * Capture Window Icon name info
441 *
442 */
list_icon_name(unsigned long * body)443 void list_icon_name(unsigned long *body)
444 {
445 if (
446 (module->window == (Window)body[1])||
447 (module->window == (Window)body[0]))
448 {
449 strncpy(target.icon_name,(char *)&body[3],255);
450 }
451 }
452
453
454 /*
455 *
456 * Capture Window class name info
457 *
458 */
list_class(unsigned long * body)459 void list_class(unsigned long *body)
460 {
461 if (
462 (module->window == (Window)body[1])||
463 (module->window == (Window)body[0]))
464 {
465 strncpy(target.class,(char *)&body[3],255);
466 }
467 }
468
469
470 /*
471 *
472 * Capture Window resource info
473 *
474 */
list_res_name(unsigned long * body)475 void list_res_name(unsigned long *body)
476 {
477 if ((module->window == (Window)body[1])||
478 (module->window == (Window)body[0]))
479 {
480 strncpy(target.res,(char *)&body[3],255);
481 }
482 }
483
list_property_change(unsigned long * body)484 void list_property_change(unsigned long *body)
485 {
486 if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND && body[2] == 0 &&
487 CSET_IS_TRANSPARENT_PR(colorset))
488 {
489 if (UsePixmapDrawing)
490 {
491 PixmapDrawWindow(
492 main_width, main_height);
493 }
494 else
495 {
496 UpdateBackgroundTransparency(
497 dpy, main_win, main_width,
498 main_height,
499 &Colorset[(colorset)], Pdepth,
500 gc, True);
501 }
502 }
503 }
504
list_config_info(unsigned long * body)505 void list_config_info(unsigned long *body)
506 {
507 char *tline, *token;
508
509 tline = (char*)&body[3];
510 tline = GetNextToken(tline, &token);
511 if (StrEquals(token, "Colorset") && colorset >= 0 &&
512 LoadColorset(tline) == colorset)
513 {
514 if (FftSupport && Ffont->fftf.fftfont != NULL)
515 {
516 UsePixmapDrawing = True;
517 }
518 /* track all colorset changes & update display if necessary */
519 /* ask for movement events iff transparent */
520 if (CSET_IS_TRANSPARENT(colorset))
521 {
522
523 mw_events |= StructureNotifyMask;
524 if (CSET_IS_TRANSPARENT_PR_PURE(colorset))
525 {
526 UsePixmapDrawing = False;
527 }
528 }
529 else
530 {
531 mw_events &= ~(StructureNotifyMask);
532 }
533 if (UsePixmapDrawing)
534 {
535 #if 0
536 mw_events &= ~(ExposureMask);
537 #endif
538 }
539 else
540 {
541 mw_events |= ExposureMask;
542 }
543 XSelectInput(dpy, main_win, mw_events);
544 XSetForeground(dpy, gc, Colorset[colorset].fg);
545 if (UsePixmapDrawing)
546 {
547 PixmapDrawWindow(main_width, main_height);
548 }
549 else
550 {
551 SetWindowBackground(
552 dpy, main_win, main_width, main_height,
553 &Colorset[colorset], Pdepth, gc, True);
554 }
555 }
556 free(token);
557 }
558
559 /*
560 *
561 * Process X Events
562 *
563 */
ProcessXEvent(int x,int y)564 int ProcessXEvent(int x, int y)
565 {
566 XEvent Event,event;
567 static int is_key_pressed = 0;
568 static int is_button_pressed = 0;
569 char buf[32];
570 static int ex=10000, ey=10000, ex2=0, ey2=0;
571
572 while (FPending(dpy))
573 {
574 FNextEvent(dpy,&Event);
575 switch(Event.type)
576 {
577 case Expose:
578 ex = min(ex, Event.xexpose.x);
579 ey = min(ey, Event.xexpose.y);
580 ex2 = max(ex2, Event.xexpose.x + Event.xexpose.width);
581 ey2=max(ey2 , Event.xexpose.y + Event.xexpose.height);
582 while (FCheckTypedEvent(dpy, Expose, &Event))
583 {
584 ex = min(ex, Event.xexpose.x);
585 ey = min(ey, Event.xexpose.y);
586 ex2 = max(
587 ex2,
588 Event.xexpose.x + Event.xexpose.width);
589 ey2=max(ey2,
590 Event.xexpose.y + Event.xexpose.height);
591 }
592 if (FftSupport && Ffont->fftf.fftfont != NULL)
593 {
594 XClearArea(
595 dpy, main_win,
596 ex, ey, ex2-ex, ey2-ey, False);
597 }
598 DrawItems(main_win, ex, ey, ex2-ex, ey2-ey);
599 ex = ey = 10000;
600 ex2 = ey2 = 0;
601 break;
602 case KeyPress:
603 is_key_pressed = 1;
604 break;
605 case ButtonPress:
606 is_button_pressed = Event.xbutton.button;
607 break;
608 case KeyRelease:
609 if (is_key_pressed)
610 {
611 exit(0);
612 }
613 break;
614 case ButtonRelease:
615 if (is_button_pressed)
616 {
617 if (is_button_pressed == 2 &&
618 Event.xbutton.button == 2)
619 {
620 /* select a new window when
621 * button 2 is pressed */
622 SetMessageMask(
623 fd, M_CONFIGURE_WINDOW |
624 M_WINDOW_NAME |
625 M_ICON_NAME |
626 M_RES_CLASS |
627 M_RES_NAME |
628 M_END_WINDOWLIST |
629 M_CONFIG_INFO |
630 M_END_CONFIG_INFO|
631 M_SENDCONFIG);
632 SendText(fd, "Send_WindowList", 0);
633 XDestroyWindow(dpy, main_win);
634 DestroyList();
635 fvwmlib_get_target_window(
636 dpy, screen, module->name,
637 &(module->window), True);
638 found = 0;
639 return 1;
640 }
641 else
642 {
643 exit(0);
644 }
645 }
646 break;
647 case ClientMessage:
648 if (Event.xclient.format==32 &&
649 Event.xclient.data.l[0]==wm_del_win)
650 {
651 exit(0);
652 }
653 break;
654 case ReparentNotify:
655 if (minimal_layer >= 0)
656 {
657 sprintf(buf, "Layer 0 %d", my_layer);
658 SendText(fd, buf, main_win);
659 }
660 SendText(fd, "Raise", main_win);
661 break;
662 case ConfigureNotify:
663 fev_sanitise_configure_notify(&Event.xconfigure);
664 /* this only happens with transparent windows,
665 * slurp up as many events as possible before
666 * redrawing to reduce flickering */
667 while (FCheckTypedEvent(
668 dpy, ConfigureNotify, &event))
669 {
670 fev_sanitise_configure_notify(
671 &event.xconfigure);
672 if (!event.xconfigure.send_event)
673 continue;
674 Event.xconfigure.x = event.xconfigure.x;
675 Event.xconfigure.y = event.xconfigure.y;
676 Event.xconfigure.send_event = True;
677 }
678 /* Only refresh if moved */
679 if ((Event.xconfigure.send_event ||
680 CSET_IS_TRANSPARENT_PR_PURE(colorset)) &&
681 (x != Event.xconfigure.x ||
682 y != Event.xconfigure.y))
683 {
684 static Bool is_initial_cn = True;
685 Bool do_eat_expose = False;
686
687 x = Event.xconfigure.x;
688 y = Event.xconfigure.y;
689 /* flush any expose events */
690 if (UsePixmapDrawing)
691 {
692 PixmapDrawWindow(
693 main_width, main_height);
694 do_eat_expose = True;
695 }
696 else if (colorset == -1)
697 {
698 do_eat_expose = True;
699 }
700 else if (UpdateBackgroundTransparency(
701 dpy, main_win, main_width,
702 main_height,
703 &Colorset[(colorset)], Pdepth,
704 gc, True) == True)
705 {
706 do_eat_expose = True;
707 }
708 if (do_eat_expose == True &&
709 is_initial_cn == False)
710 {
711 while (FCheckTypedEvent(
712 dpy, Expose, &Event))
713 {
714 /* nothing */
715 }
716 }
717 is_initial_cn = False;
718 }
719 break;
720 }
721 }
722 XFlush (dpy);
723
724 return 0;
725 }
726
727 /*
728 *
729 * End of window list, open an x window and display data in it
730 *
731 */
list_end(void)732 void list_end(void)
733 {
734 XSizeHints mysizehints;
735 XGCValues gcv;
736 unsigned long gcm;
737 int lmax,height;
738 int x,y;
739 XSetWindowAttributes attributes;
740
741 if(!found)
742 {
743 exit(0);
744 }
745
746 /* tell fvwm to only send config messages */
747 SetMessageMask(fd, M_CONFIG_INFO | M_SENDCONFIG);
748
749 if ((Ffont = FlocaleLoadFont(dpy, font_string, module->name)) == NULL)
750 {
751 fvwm_debug(__func__, "%s: cannot load font, exiting\n",
752 module->name);
753 exit(1);
754 }
755
756 /* chose the rendering methode */
757 if (FftSupport && Ffont->fftf.fftfont != NULL)
758 {
759 UsePixmapDrawing = True;
760 }
761 /* make window infomation list */
762 MakeList();
763
764 /* size and create the window */
765 lmax = max_col1 + max_col2 + 15;
766
767 height = ListSize * (Ffont->height);
768
769 mysizehints.flags=
770 USSize|USPosition|PWinGravity|PResizeInc|PBaseSize|PMinSize|
771 PMaxSize;
772 main_width = mysizehints.width = lmax + 10;
773 main_height = mysizehints.height = height + 10;
774 mysizehints.width_inc = 1;
775 mysizehints.height_inc = 1;
776 mysizehints.base_height = mysizehints.height;
777 mysizehints.base_width = mysizehints.width;
778 mysizehints.min_height = mysizehints.height;
779 mysizehints.min_width = mysizehints.width;
780 mysizehints.max_height = mysizehints.height;
781 mysizehints.max_width = mysizehints.width;
782 mysizehints.win_gravity = NorthWestGravity;
783 {
784 int sx;
785 int sy;
786 int sw;
787 int sh;
788 Window JunkW;
789 int JunkC;
790 unsigned int JunkM;
791 fscreen_scr_arg fscr;
792
793 if (!FQueryPointer(
794 dpy, Root, &JunkW, &JunkW, &x, &y, &JunkC, &JunkC,
795 &JunkM))
796 {
797 /* pointer is on a different screen */
798 x = 0;
799 y = 0;
800 }
801
802 fscr.xypos.x = x;
803 fscr.xypos.y = y;
804 FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &sx, &sy, &sw, &sh);
805 if (y + height + 100 > sy + sh)
806 {
807 y = sy + sh - height - 10;
808 mysizehints.win_gravity = SouthWestGravity;
809 }
810 if (x + lmax + 100 > sx + sw)
811 {
812 x = sx + sw - lmax - 10;
813 if (mysizehints.win_gravity == SouthWestGravity)
814 mysizehints.win_gravity = SouthEastGravity;
815 else
816 mysizehints.win_gravity = NorthEastGravity;
817 }
818 }
819
820 if (Pdepth < 2)
821 {
822 back_pix = GetColor("white");
823 fore_pix = GetColor("black");
824 }
825 else
826 {
827 back_pix = (colorset < 0)?
828 GetColor(BackColor) : Colorset[colorset].bg;
829 fore_pix = (colorset < 0)?
830 GetColor(ForeColor) : Colorset[colorset].fg;
831 }
832
833 attributes.colormap = Pcmap;
834 attributes.border_pixel = 0;
835 attributes.background_pixel = back_pix;
836 main_win = XCreateWindow(
837 dpy, Root, x, y, mysizehints.width, mysizehints.height, 0,
838 Pdepth, InputOutput, Pvisual, CWColormap | CWBackPixel |
839 CWBorderPixel, &attributes);
840 wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
841 XSetWMProtocols(dpy,main_win,&wm_del_win,1);
842
843 /* hack to prevent mapping on wrong screen with StartsOnScreen */
844 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &mysizehints);
845 XSetWMNormalHints(dpy,main_win,&mysizehints);
846 /* have to ask for configure events when transparent */
847 if (CSET_IS_TRANSPARENT(colorset))
848 {
849 mw_events |= StructureNotifyMask;
850 if (CSET_IS_TRANSPARENT_PR_PURE(colorset))
851 {
852 UsePixmapDrawing = 0;
853 }
854 }
855 if (!UsePixmapDrawing)
856 {
857 mw_events |= ExposureMask;
858 }
859
860 XSelectInput(dpy, main_win, mw_events);
861 change_window_name(module->name);
862
863 gcm = GCForeground;
864 gcv.foreground = fore_pix;
865 if (Ffont->font != NULL)
866 {
867 gcm |= GCFont;
868 gcv.font = Ffont->font->fid;
869 }
870 gc = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
871 if (UsePixmapDrawing)
872 {
873 PixmapDrawWindow(main_width, main_height);
874 }
875 else if (colorset >= 0)
876 {
877 SetWindowBackground(
878 dpy, main_win, main_width, main_height,
879 &Colorset[(colorset)], Pdepth, gc, True);
880 }
881 XMapWindow(dpy,main_win);
882
883 /* Window is created. Display it until the user clicks or deletes it.
884 * also grok any dynamic config changes */
885 while(1)
886 {
887 FvwmPacket* packet;
888 int x_fd = XConnectionNumber(dpy);
889 fd_set fdset;
890
891 FD_ZERO(&fdset);
892 FD_SET(fd[1], &fdset);
893 FD_SET(x_fd, &fdset);
894
895 /* process all X events first */
896 if (ProcessXEvent(x,y) == 1)
897 {
898 return;
899 }
900
901 /* wait for X-event or config line */
902 select(fd_width, SELECT_FD_SET_CAST &fdset, NULL, NULL, NULL );
903
904 /* parse any dynamic config lines */
905 if (FD_ISSET(fd[1], &fdset))
906 {
907 packet = ReadFvwmPacket(fd[1]);
908 if (packet == NULL)
909 exit(0);
910 if (packet && packet->type == MX_PROPERTY_CHANGE)
911 {
912 list_property_change(packet->body);
913 }
914 if (packet && packet->type == M_CONFIG_INFO)
915 {
916 list_config_info(packet->body);
917 }
918 }
919 }
920 }
921
922 /*
923 *
924 * Draw the items
925 *
926 */
DrawItems(Drawable d,int x,int y,int w,int h)927 void DrawItems(Drawable d, int x, int y, int w, int h)
928 {
929 int fontheight,i=0;
930 struct Item *cur = itemlistRoot;
931 Region region = 0;
932
933 fontheight = Ffont->height;
934 FwinString->win = d;
935 FwinString->gc = gc;
936 FwinString->flags.has_clip_region = False;
937 if (w > 0)
938 {
939 XRectangle r;
940
941 r.x = x;
942 r.y = y;
943 r.width = w;
944 r.height = h;
945
946 region = XCreateRegion();
947 XUnionRectWithRegion(&r, region, region);
948 XSetRegion(dpy, gc, region);
949 FwinString->flags.has_clip_region = True;
950 FwinString->clip_region = region;
951 }
952
953 if (colorset >= 0)
954 {
955 FwinString->colorset = &Colorset[colorset];
956 FwinString->flags.has_colorset = True;
957 }
958 while(cur != NULL) /* may be optimised */
959 {
960 /* first column */
961 FwinString->str = cur->col1;
962 FwinString->x = 5;
963 FwinString->y = 5 + Ffont->ascent + i * fontheight;
964 FlocaleDrawString(dpy, Ffont, FwinString, 0);
965
966 /* second column */
967 FwinString->str = cur->col2;
968 FwinString->x = 10 + max_col1;
969 FlocaleDrawString(dpy, Ffont, FwinString, 0);
970
971 ++i;
972 cur = cur->next;
973 }
974 if (FwinString->flags.has_clip_region)
975 {
976 XDestroyRegion(region);
977 XSetClipMask(dpy, gc, None);
978 }
979 XFlush (dpy);
980 }
981
PixmapDrawWindow(int w,int h)982 void PixmapDrawWindow(int w, int h)
983 {
984 Pixmap pix;
985 XGCValues gcv;
986 unsigned long gcm;
987
988 if (colorset >= 0)
989 {
990 Pixmap cs_pix;
991 cs_pix = CreateBackgroundPixmap(dpy, main_win, w, h,
992 &Colorset[(colorset)],
993 Pdepth, gc, False);
994 if (cs_pix == ParentRelative)
995 {
996 pix = cs_pix;
997 }
998 else
999 {
1000 pix = CreateTiledPixmap(
1001 dpy, cs_pix, 0,0,w,h,Pdepth, gc);
1002 XFreePixmap(dpy, cs_pix);
1003 }
1004 }
1005 else
1006 {
1007 gcm = GCForeground;
1008 gcv.foreground = back_pix;
1009 XChangeGC(dpy, gc, gcm, &gcv);
1010 pix = XCreatePixmap(dpy, main_win, w, h, Pdepth);
1011 XFillRectangle(dpy, pix, gc, 0, 0, w, h);
1012 gcv.foreground = fore_pix;
1013 XChangeGC(dpy, gc, gcm, &gcv);
1014 }
1015
1016 if (pix != ParentRelative)
1017 {
1018 DrawItems(pix, 0, 0, 0, 0);
1019 XSetWindowBackgroundPixmap(dpy, main_win, pix);
1020 XClearWindow(dpy, main_win);
1021 XFreePixmap(dpy, pix);
1022 }
1023 else
1024 {
1025 XSetWindowBackgroundPixmap(dpy, main_win, pix);
1026 XClearWindow(dpy, main_win);
1027 DrawItems(main_win, 0, 0, 0, 0);
1028 }
1029 }
1030
1031 /*
1032 * Change the window name displayed in the title bar.
1033 */
change_window_name(char * str)1034 void change_window_name(char *str)
1035 {
1036 XTextProperty name;
1037 XClassHint myclasshints;
1038
1039 if (XStringListToTextProperty(&str,1,&name) == 0)
1040 {
1041 fvwm_debug(__func__, "%s: cannot allocate window name",
1042 module->name);
1043 return;
1044 }
1045 XSetWMName(dpy,main_win,&name);
1046 XSetWMIconName(dpy,main_win,&name);
1047 XFree(name.value);
1048 myclasshints.res_name = str;
1049 myclasshints.res_class = "FvwmIdent";
1050 XSetClassHint(dpy,main_win,&myclasshints);
1051 }
1052
1053
DestroyList(void)1054 void DestroyList(void)
1055 {
1056 struct Item *t;
1057 struct Item *tmp;
1058
1059 for (t = itemlistRoot; t; t = tmp)
1060 {
1061 tmp = t->next;
1062 free(t);
1063 }
1064 itemlistRoot = NULL;
1065 }
1066
1067 /*
1068 *
1069 * Add s1(string at first column) and s2(string at second column) to itemlist
1070 *
1071 */
AddToList(char * s1,char * s2)1072 void AddToList(char *s1, char* s2)
1073 {
1074 int tw1, tw2;
1075 struct Item* item, *cur = itemlistRoot;
1076
1077 tw1 = FlocaleTextWidth(Ffont, s1, strlen(s1));
1078 tw2 = FlocaleTextWidth(Ffont, s2, strlen(s2));
1079 max_col1 = max_col1 > tw1 ? max_col1 : tw1;
1080 max_col2 = max_col2 > tw2 ? max_col2 : tw2;
1081
1082 item = fxmalloc(sizeof(struct Item));
1083 item->col1 = s1;
1084 item->col2 = s2;
1085 item->next = NULL;
1086
1087 if (cur == NULL)
1088 {
1089 itemlistRoot = item;
1090 }
1091 else
1092 {
1093 while(cur->next != NULL)
1094 {
1095 cur = cur->next;
1096 }
1097 cur->next = item;
1098 }
1099 ListSize++;
1100 }
1101
MakeList(void)1102 void MakeList(void)
1103 {
1104 int bw,width,height,x1,y1,x2,y2;
1105 char loc[24];
1106 static char xstr[21],ystr[21];
1107 /* GSFR - quick hack because the new macros depend on a prt reference
1108 */
1109 struct target_struct *targ = ⌖
1110
1111 ListSize = 0;
1112
1113 bw = 2*target.border_w;
1114 width = target.frame_w - bw;
1115 height = target.frame_h - bw;
1116 if (target.title_dir == DIR_W || target.title_dir == DIR_E)
1117 {
1118 width -= target.title_h;
1119 }
1120 else if (target.title_dir == DIR_N || target.title_dir == DIR_S)
1121 {
1122 height -= target.title_h;
1123 }
1124
1125 sprintf(desktop, "%ld", target.desktop);
1126 sprintf(layer, "%ld", target.layer);
1127 sprintf(id, "0x%x", (unsigned int)target.id);
1128 sprintf(swidth, "%d", width);
1129 sprintf(sheight, "%d", height);
1130 sprintf(borderw, "%ld", target.border_w);
1131 sprintf(xstr, "%ld", target.frame_x);
1132 sprintf(ystr, "%ld", target.frame_y);
1133
1134 AddToList("Name:", target.name);
1135 AddToList("Icon Name:", target.icon_name);
1136 AddToList("Class:", target.class);
1137 AddToList("Resource:", target.res);
1138 AddToList("Window ID:", id);
1139 AddToList("Monitor:", target.monitor);
1140 AddToList("Desk:", desktop);
1141 AddToList("Layer:", layer);
1142 AddToList("Width:", swidth);
1143 AddToList("Height:", sheight);
1144 AddToList("X (current page):", xstr);
1145 AddToList("Y (current page):", ystr);
1146 AddToList("Boundary Width:", borderw);
1147
1148 AddToList("StickyPage:", (IS_STICKY_ACROSS_PAGES(targ) ? yes : no));
1149 AddToList("StickyDesk:", (IS_STICKY_ACROSS_DESKS(targ) ? yes : no));
1150 AddToList("StickyPageIcon:",
1151 (IS_ICON_STICKY_ACROSS_PAGES(targ) ? yes : no));
1152 AddToList("StickyDeskIcon:",
1153 (IS_ICON_STICKY_ACROSS_DESKS(targ) ? yes : no));
1154 AddToList("NoTitle:", (HAS_TITLE(targ) ? no : yes));
1155 AddToList("Iconified:", (IS_ICONIFIED(targ) ? yes : no));
1156 AddToList("Transient:", (IS_TRANSIENT(targ) ? yes : no));
1157 AddToList("WindowListSkip:", (DO_SKIP_WINDOW_LIST(targ) ? yes : no));
1158
1159 switch(target.gravity)
1160 {
1161 case ForgetGravity:
1162 AddToList("Gravity:", "Forget");
1163 break;
1164 case NorthWestGravity:
1165 AddToList("Gravity:", "NorthWest");
1166 break;
1167 case NorthGravity:
1168 AddToList("Gravity:", "North");
1169 break;
1170 case NorthEastGravity:
1171 AddToList("Gravity:", "NorthEast");
1172 break;
1173 case WestGravity:
1174 AddToList("Gravity:", "West");
1175 break;
1176 case CenterGravity:
1177 AddToList("Gravity:", "Center");
1178 break;
1179 case EastGravity:
1180 AddToList("Gravity:", "East");
1181 break;
1182 case SouthWestGravity:
1183 AddToList("Gravity:", "SouthWest");
1184 break;
1185 case SouthGravity:
1186 AddToList("Gravity:", "South");
1187 break;
1188 case SouthEastGravity:
1189 AddToList("Gravity:", "SouthEast");
1190 break;
1191 case StaticGravity:
1192 AddToList("Gravity:", "Static");
1193 break;
1194 default:
1195 AddToList("Gravity:", "Unknown");
1196 break;
1197 }
1198 x1 = target.frame_x;
1199 if(x1 < 0)
1200 {
1201 x1 = 0;
1202 }
1203 x2 = DisplayWidth(dpy,screen) - x1 - target.frame_w;
1204 if(x2 < 0)
1205 {
1206 x2 = 0;
1207 }
1208 y1 = target.frame_y;
1209 if(y1 < 0)
1210 {
1211 y1 = 0;
1212 }
1213 y2 = DisplayHeight(dpy,screen) - y1 - target.frame_h;
1214 if(y2 < 0)
1215 {
1216 y2 = 0;
1217 }
1218 width = (width - target.base_w)/target.width_inc;
1219 height = (height - target.base_h)/target.height_inc;
1220
1221 sprintf(loc,"%dx%d",width,height);
1222 strcpy(geometry, loc);
1223
1224 if ((target.gravity == EastGravity) ||
1225 (target.gravity == NorthEastGravity)||
1226 (target.gravity == SouthEastGravity))
1227 {
1228 sprintf(loc,"-%d",x2);
1229 }
1230 else
1231 {
1232 sprintf(loc,"+%d",x1);
1233 }
1234 strcat(geometry, loc);
1235
1236 if((target.gravity == SouthGravity)||
1237 (target.gravity == SouthEastGravity)||
1238 (target.gravity == SouthWestGravity))
1239 {
1240 sprintf(loc,"-%d",y2);
1241 }
1242 else
1243 {
1244 sprintf(loc,"+%d",y1);
1245 }
1246 strcat(geometry, loc);
1247 AddToList("Geometry:", geometry);
1248
1249 {
1250 Atom *protocols = NULL, *ap;
1251 Atom _XA_WM_TAKE_FOCUS = XInternAtom(
1252 dpy, "WM_TAKE_FOCUS", False);
1253 XWMHints *wmhintsp = XGetWMHints(dpy,target.id);
1254 int i,n;
1255 Boolean HasTakeFocus=False,InputField=True;
1256 char *focus_policy="",*ifstr="",*tfstr="";
1257
1258 if (wmhintsp)
1259 {
1260 InputField=wmhintsp->input;
1261 ifstr=InputField?"True":"False";
1262 XFree(wmhintsp);
1263 }
1264 else
1265 {
1266 ifstr="XWMHints missing";
1267 }
1268 if (XGetWMProtocols(dpy,target.id,&protocols,&n))
1269 {
1270 for (i = 0, ap = protocols; i < n; i++, ap++)
1271 {
1272 if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
1273 HasTakeFocus = True;
1274 }
1275 tfstr=HasTakeFocus?"Present":"Absent";
1276 XFree(protocols);
1277 }
1278 else
1279 {
1280 tfstr="XGetWMProtocols failed";
1281 }
1282 if (HasTakeFocus)
1283 {
1284 if (InputField)
1285 {
1286 focus_policy = "Locally Active";
1287 }
1288 else
1289 {
1290 focus_policy = "Globally Active";
1291 }
1292 }
1293 else
1294 {
1295 if (InputField)
1296 {
1297 focus_policy = "Passive";
1298 }
1299 else
1300 {
1301 focus_policy = "No Input";
1302 }
1303 }
1304 AddToList("Focus Policy:",focus_policy);
1305 AddToList(" - Input Field:",ifstr);
1306 AddToList(" - WM_TAKE_FOCUS:",tfstr);
1307 {
1308 /* flags hints that were supplied */
1309 long supplied_return;
1310 int getrc;
1311 XSizeHints *size_hints =
1312 XAllocSizeHints(); /* the size hints */
1313 if ((getrc = XGetWMSizeHints(
1314 dpy,target.id, /* get size hints */
1315 size_hints, /* Hints */
1316 &supplied_return,
1317 XA_WM_ZOOM_HINTS)))
1318 {
1319 if (supplied_return & PAspect)
1320 { /* if window has a aspect ratio */
1321 sprintf(
1322 mymin_aspect, "%d/%d",
1323 size_hints->min_aspect.x,
1324 size_hints->min_aspect.y);
1325 AddToList(
1326 "Minimum aspect ratio:",
1327 mymin_aspect);
1328 sprintf(
1329 max_aspect, "%d/%d",
1330 size_hints->max_aspect.x,
1331 size_hints->max_aspect.y);
1332 AddToList(
1333 "Maximum aspect ratio:",
1334 max_aspect);
1335 } /* end aspect ratio */
1336 XFree(size_hints);
1337 } /* end getsizehints worked */
1338 }
1339 }
1340
1341 /* EWMH window type */
1342 if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DESKTOP_ID)
1343 AddToList("EWMH Window Type:","Desktop");
1344 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DIALOG_ID)
1345 AddToList("EWMH Window Type:","Dialog");
1346 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DOCK_ID)
1347 AddToList("EWMH Window Type:","Dock");
1348 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_MENU_ID)
1349 AddToList("EWMH Window Type:","Menu");
1350 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_NORMAL_ID)
1351 AddToList("EWMH Window Type:","Normal");
1352 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_TOOLBAR_ID)
1353 AddToList("EWMH Window Type:","ToolBar");
1354
1355 /* EWMH wm state */
1356 ewmh_init_state[0] = '\0';
1357 if (HAS_EWMH_INIT_FULLSCREEN_STATE(targ) == EWMH_STATE_HAS_HINT)
1358 {
1359 strcat(ewmh_init_state, "FullScreen ");
1360 }
1361 if (HAS_EWMH_INIT_HIDDEN_STATE(targ) == EWMH_STATE_HAS_HINT)
1362 {
1363 strcat(ewmh_init_state, "Iconic ");
1364 }
1365 if (HAS_EWMH_INIT_MAXHORIZ_STATE(targ) == EWMH_STATE_HAS_HINT)
1366 {
1367 strcat(ewmh_init_state, "MaxHoriz ");
1368 }
1369 if (HAS_EWMH_INIT_MAXVERT_STATE(targ) == EWMH_STATE_HAS_HINT)
1370 {
1371 strcat(ewmh_init_state, "MaxVert ");
1372 }
1373 if (HAS_EWMH_INIT_MODAL_STATE(targ) == EWMH_STATE_HAS_HINT)
1374 {
1375 strcat(ewmh_init_state, "Modal ");
1376 }
1377 if (HAS_EWMH_INIT_SHADED_STATE(targ)== EWMH_STATE_HAS_HINT)
1378 {
1379 strcat(ewmh_init_state, "Shaded ");
1380 }
1381 if (HAS_EWMH_INIT_SKIP_PAGER_STATE(targ) == EWMH_STATE_HAS_HINT ||
1382 HAS_EWMH_INIT_SKIP_TASKBAR_STATE(targ) == EWMH_STATE_HAS_HINT )
1383 {
1384 strcat(ewmh_init_state, "SkipList ");
1385 }
1386 if (HAS_EWMH_INIT_STICKY_STATE(targ) == EWMH_STATE_HAS_HINT ||
1387 (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT &&
1388 (target.ewmh_hint_desktop == (unsigned long)-2 ||
1389 target.ewmh_hint_desktop == (unsigned long)-1)))
1390 {
1391 strcat(ewmh_init_state, "Sticky ");
1392 }
1393 /* FIXME: we should use the fvwm default layers */
1394 if (target.ewmh_hint_layer == 6)
1395 {
1396 strcat(ewmh_init_state, "StaysOnTop ");
1397 }
1398 else if (target.ewmh_hint_layer == 2)
1399 {
1400 strcat(ewmh_init_state, "StaysOnBottom ");
1401 }
1402 if (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT &&
1403 target.ewmh_hint_desktop < 256)
1404 {
1405 char desk_buf[32];
1406 snprintf(desk_buf, 32, "StartOnDesk %lu ", target.ewmh_hint_desktop);
1407 strcat(ewmh_init_state, desk_buf);
1408 }
1409 if (ewmh_init_state[0] != '\0')
1410 {
1411 /* remove ending space */
1412 ewmh_init_state[strlen(ewmh_init_state)-1] = '\0';
1413 AddToList("EWMH Init State:",ewmh_init_state);
1414 }
1415 }
1416
1417 /*
1418 X Error Handler
1419 */
1420 static int
ErrorHandler(Display * d,XErrorEvent * event)1421 ErrorHandler(Display *d, XErrorEvent *event)
1422 {
1423 #if 0
1424 if (event->error_code == BadPixmap)
1425 {
1426 return 0;
1427 }
1428 if (event->error_code == BadDrawable)
1429 {
1430 return 0;
1431 }
1432 if (event->error_code == FRenderGetErrorCodeBase() + FRenderBadPicture)
1433 {
1434 return 0;
1435 }
1436 #endif
1437
1438 PrintXErrorAndCoredump(d, event, module->name);
1439 return 0;
1440 }
1441