Propagate Layer changes via Style command on-the-fly.
[fvwm.git] / modules / FvwmIdent / FvwmIdent.c
blob6c5bf5ca67780d4484561a31f82ee7469a32b1f4
1 /* -*-c-*- */
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>
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. */
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.
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.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "config.h"
30 #include <stdio.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #include <sys/wait.h>
34 #include "libs/ftime.h"
36 #if HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif
40 #include <unistd.h>
41 #include <ctype.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xutil.h>
44 #include <X11/Xproto.h>
45 #include <X11/Xatom.h>
46 #include <X11/Intrinsic.h>
47 #include <X11/cursorfont.h>
48 #include <X11/keysym.h>
50 #include "libs/fvwmlib.h"
51 #include "libs/FScreen.h"
52 #include "libs/FShape.h"
53 #include "libs/Module.h"
54 #include "libs/Colorset.h"
55 #include "libs/fvwmsignal.h"
56 #include "libs/Flocale.h"
57 #include "libs/Parse.h"
58 #include "libs/FRenderInit.h"
59 #include "libs/Graphics.h"
60 #include "libs/System.h"
61 #include "libs/Target.h"
62 #include "libs/XError.h"
64 #include "FvwmIdent.h"
66 static RETSIGTYPE TerminateHandler(int);
68 static ModuleArgs *module;
69 static fd_set_size_t fd_width;
70 static int fd[2];
72 static Display *dpy; /* which display are we talking to */
73 static Window Root;
74 static GC gc;
76 static FlocaleFont *Ffont;
77 static FlocaleWinString *FwinString;
79 static int screen;
80 static int x_fd;
82 static char *yes = "Yes";
83 static char *no = "No";
85 /* default colorset to use, set to -1 when explicitly setting colors */
86 static int colorset = 0;
88 static char *BackColor = "white";
89 static char *ForeColor = "black";
90 static char *font_string = NULL;
92 static Pixel fore_pix;
93 static Pixel back_pix;
94 static Window main_win;
95 static Bool UsePixmapDrawing = False; /* if True draw everything in a pixmap
96 * and set the window background. Use
97 * this with Xft */
98 static int main_width;
99 static int main_height;
101 static EventMask mw_events =
102 ExposureMask | ButtonPressMask | KeyPressMask |
103 ButtonReleaseMask | KeyReleaseMask | StructureNotifyMask;
105 static Atom wm_del_win;
107 static struct target_struct target;
108 static int found=0;
110 static int ListSize=0;
112 static struct Item* itemlistRoot = NULL;
113 static int max_col1, max_col2;
114 static char id[15], desktop[10], swidth[10], sheight[10], borderw[10];
115 static char geometry[30], mymin_aspect[11], max_aspect[11], layer[10];
116 static char ewmh_init_state[512];
118 /* FIXME: default layer should be received from fvwm */
119 #define default_layer DEFAULT_DEFAULT_LAYER
120 static int minimal_layer = default_layer;
121 static int my_layer = default_layer;
125 * Procedure:
126 * main - start of module
129 int main(int argc, char **argv)
131 char *display_name = NULL;
132 char *tline;
134 FlocaleInit(LC_CTYPE, "", "", "FvwmIdent");
136 module = ParseModuleArgs(argc,argv,0); /* no alias */
137 if (module == NULL)
139 fprintf(
140 stderr, "FvwmIdent Version %s should only be executed"
141 " by fvwm!\n", VERSION);
142 exit(1);
145 #ifdef HAVE_SIGACTION
147 struct sigaction sigact;
149 sigemptyset(&sigact.sa_mask);
150 sigaddset(&sigact.sa_mask, SIGPIPE);
151 sigaddset(&sigact.sa_mask, SIGTERM);
152 sigaddset(&sigact.sa_mask, SIGQUIT);
153 sigaddset(&sigact.sa_mask, SIGINT);
154 sigaddset(&sigact.sa_mask, SIGHUP);
155 # ifdef SA_INTERRUPT
156 sigact.sa_flags = SA_INTERRUPT;
157 # else
158 sigact.sa_flags = 0;
159 # endif
160 sigact.sa_handler = TerminateHandler;
162 sigaction(SIGPIPE, &sigact, NULL);
163 sigaction(SIGTERM, &sigact, NULL);
164 sigaction(SIGQUIT, &sigact, NULL);
165 sigaction(SIGINT, &sigact, NULL);
166 sigaction(SIGHUP, &sigact, NULL);
168 #else
169 /* We don't have sigaction(), so fall back to less robust methods. */
170 #ifdef USE_BSD_SIGNALS
171 fvwmSetSignalMask( sigmask(SIGPIPE) |
172 sigmask(SIGTERM) |
173 sigmask(SIGQUIT) |
174 sigmask(SIGINT) |
175 sigmask(SIGHUP) );
176 #endif
177 signal(SIGPIPE, TerminateHandler);
178 signal(SIGTERM, TerminateHandler);
179 signal(SIGQUIT, TerminateHandler);
180 signal(SIGINT, TerminateHandler);
181 signal(SIGHUP, TerminateHandler);
182 #ifdef HAVE_SIGINTERRUPT
183 siginterrupt(SIGPIPE, 1);
184 siginterrupt(SIGTERM, 1);
185 siginterrupt(SIGQUIT, 1);
186 siginterrupt(SIGINT, 1);
187 siginterrupt(SIGHUP, 1);
188 #endif
189 #endif
191 fd[0] = module->to_fvwm;
192 fd[1] = module->from_fvwm;
194 /* Open the Display */
195 if (!(dpy = XOpenDisplay(display_name)))
197 fprintf(stderr,"%s: can't open display %s", module->name,
198 XDisplayName(display_name));
199 exit (1);
201 x_fd = XConnectionNumber(dpy);
202 screen= DefaultScreen(dpy);
203 Root = RootWindow(dpy, screen);
204 XSetErrorHandler(ErrorHandler);
206 flib_init_graphics(dpy);
207 FlocaleAllocateWinString(&FwinString);
209 SetMessageMask(fd, M_CONFIGURE_WINDOW | M_WINDOW_NAME | M_ICON_NAME
210 | M_RES_CLASS | M_RES_NAME | M_END_WINDOWLIST |
211 M_CONFIG_INFO | M_END_CONFIG_INFO | M_SENDCONFIG);
212 SetMessageMask(fd, MX_PROPERTY_CHANGE);
213 /* scan config file for set-up parameters */
214 /* Colors and fonts */
216 InitGetConfigLine(fd,CatString3("*",module->name,0));
217 GetConfigLine(fd,&tline);
219 while (tline != (char *)0)
221 if (strlen(tline) <= 1)
223 continue;
225 if (strncasecmp(tline,
226 CatString3("*",module->name,0),
227 module->namelen+1) == 0)
229 tline += (module->namelen +1);
230 if (strncasecmp(tline, "Font", 4) == 0)
232 CopyStringWithQuotes(&font_string, &tline[4]);
234 else if (strncasecmp(tline, "Fore", 4) == 0)
236 CopyString(&ForeColor, &tline[4]);
237 colorset = -1;
239 else if (strncasecmp(tline, "Back", 4) == 0)
241 CopyString(&BackColor, &tline[4]);
242 colorset = -1;
244 else if (strncasecmp(tline, "Colorset", 8) == 0)
246 sscanf(&tline[8], "%d", &colorset);
247 AllocColorset(colorset);
249 else if (strncasecmp(tline, "MinimalLayer", 12) == 0)
251 char *layer_str = PeekToken(&tline[12], NULL);
252 if (layer_str == NULL)
254 minimal_layer = default_layer;
256 else if (sscanf(
257 layer_str, "%d", &minimal_layer) != 1)
259 if (strncasecmp(
260 layer_str, "none", 4) == 0)
262 minimal_layer = -1;
264 else
266 minimal_layer = default_layer;
271 else if (strncasecmp(tline, "Colorset", 8) == 0)
273 LoadColorset(&tline[8]);
275 else if (strncasecmp(
276 tline, XINERAMA_CONFIG_STRING,
277 sizeof(XINERAMA_CONFIG_STRING) - 1) == 0)
279 FScreenConfigureModule(
280 tline + sizeof(XINERAMA_CONFIG_STRING) - 1);
282 GetConfigLine(fd, &tline);
285 if(module->window == 0)
287 fvwmlib_get_target_window(
288 dpy, screen, module->name, &(module->window), True);
291 fd_width = GetFdWidth();
293 /* Create a list of all windows */
294 /* Request a list of all windows,
295 * wait for ConfigureWindow packets */
296 SendText(fd, "Send_WindowList", 0);
298 /* tell fvwm we're running */
299 SendFinishedStartupNotification(fd);
300 if (module->window == Root)
302 exit(0);
305 Loop(fd);
306 return 0;
311 * Read the entire window list from fvwm
314 void Loop(int *fd)
316 while (1)
318 FvwmPacket* packet = ReadFvwmPacket(fd[1]);
319 if ( packet == NULL )
321 exit(0);
323 else
325 process_message( packet->type, packet->body );
333 * Process window list messages
336 void process_message(unsigned long type,unsigned long *body)
338 switch(type)
340 /* should turn off this packet but it comes after config_list
341 * so have to accept at least one */
342 case M_CONFIGURE_WINDOW:
343 list_configure(body);
344 break;
345 case M_WINDOW_NAME:
346 list_window_name(body);
347 break;
348 case M_ICON_NAME:
349 list_icon_name(body);
350 break;
351 case M_RES_CLASS:
352 list_class(body);
353 break;
354 case M_RES_NAME:
355 list_res_name(body);
356 break;
357 case M_END_WINDOWLIST:
358 list_end();
359 break;
360 default:
361 break;
367 * Procedure:
368 * SIGPIPE handler - SIGPIPE means fvwm is dying
371 static RETSIGTYPE
372 TerminateHandler(int sig)
374 fvwmSetTerminate(sig);
375 SIGNAL_RETURN;
380 * Got window configuration info - if its our window, save data
383 void list_configure(unsigned long *body)
385 struct ConfigWinPacket *cfgpacket = (void *) body;
387 if (
388 (module->window == cfgpacket->frame)||
389 (module->window == cfgpacket->w) ||
390 ((cfgpacket->icon_w != 0)&&
391 (module->window == cfgpacket->icon_w)) ||
392 ((cfgpacket->icon_pixmap_w)&&
393 (module->window == cfgpacket->icon_pixmap_w)))
395 module->window = cfgpacket->frame;
396 target.id = cfgpacket->w;
397 target.frame = cfgpacket->frame;
398 target.frame_x = cfgpacket->frame_x;
399 target.frame_y = cfgpacket->frame_y;
400 target.frame_w = cfgpacket->frame_width;
401 target.frame_h = cfgpacket->frame_height;
402 target.desktop = cfgpacket->desk;
403 target.layer = cfgpacket->layer;
404 memcpy(&target.flags,
405 &(cfgpacket->flags), sizeof(cfgpacket->flags));
406 target.title_h = cfgpacket->title_height;
407 target.title_dir = GET_TITLE_DIR(cfgpacket);
408 target.border_w = cfgpacket->border_width;
409 target.base_w = cfgpacket->hints_base_width;
410 target.base_h = cfgpacket->hints_base_height;
411 target.width_inc = cfgpacket->orig_hints_width_inc;
412 target.height_inc = cfgpacket->orig_hints_height_inc;
413 target.gravity = cfgpacket->hints_win_gravity;
414 target.ewmh_hint_layer = cfgpacket->ewmh_hint_layer;
415 target.ewmh_hint_desktop = cfgpacket->ewmh_hint_desktop;
416 target.ewmh_window_type = cfgpacket->ewmh_window_type;
417 found = 1;
419 my_layer = (int)target.layer;
420 if (my_layer < minimal_layer)
422 my_layer = minimal_layer;
429 * Capture Window name info
432 void list_window_name(unsigned long *body)
434 if (
435 (module->window == (Window)body[1])||
436 (module->window == (Window)body[0]))
438 strncpy(target.name,(char *)&body[3],255);
444 * Capture Window Icon name info
447 void list_icon_name(unsigned long *body)
449 if (
450 (module->window == (Window)body[1])||
451 (module->window == (Window)body[0]))
453 strncpy(target.icon_name,(char *)&body[3],255);
460 * Capture Window class name info
463 void list_class(unsigned long *body)
465 if (
466 (module->window == (Window)body[1])||
467 (module->window == (Window)body[0]))
469 strncpy(target.class,(char *)&body[3],255);
476 * Capture Window resource info
479 void list_res_name(unsigned long *body)
481 if ((module->window == (Window)body[1])||
482 (module->window == (Window)body[0]))
484 strncpy(target.res,(char *)&body[3],255);
488 void list_property_change(unsigned long *body)
490 if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND && body[2] == 0 &&
491 CSET_IS_TRANSPARENT_PR(colorset))
493 if (UsePixmapDrawing)
495 PixmapDrawWindow(
496 main_width, main_height);
498 else
500 UpdateBackgroundTransparency(
501 dpy, main_win, main_width,
502 main_height,
503 &Colorset[(colorset)], Pdepth,
504 gc, True);
509 void list_config_info(unsigned long *body)
511 char *tline, *token;
513 tline = (char*)&body[3];
514 tline = GetNextToken(tline, &token);
515 if (StrEquals(token, "Colorset") && colorset >= 0 &&
516 LoadColorset(tline) == colorset)
518 if (FftSupport && Ffont->fftf.fftfont != NULL)
520 UsePixmapDrawing = True;
522 /* track all colorset changes & update display if necessary */
523 /* ask for movement events iff transparent */
524 if (CSET_IS_TRANSPARENT(colorset))
527 mw_events |= StructureNotifyMask;
528 if (CSET_IS_TRANSPARENT_PR_PURE(colorset))
530 UsePixmapDrawing = False;
533 else
535 mw_events &= ~(StructureNotifyMask);
537 if (UsePixmapDrawing)
539 #if 0
540 mw_events &= ~(ExposureMask);
541 #endif
543 else
545 mw_events |= ExposureMask;
547 XSelectInput(dpy, main_win, mw_events);
548 XSetForeground(dpy, gc, Colorset[colorset].fg);
549 if (UsePixmapDrawing)
551 PixmapDrawWindow(main_width, main_height);
553 else
555 SetWindowBackground(
556 dpy, main_win, main_width, main_height,
557 &Colorset[colorset], Pdepth, gc, True);
560 else if (StrEquals(token, XINERAMA_CONFIG_STRING))
562 FScreenConfigureModule(tline);
564 if (token)
565 free(token);
570 * Process X Events
573 int ProcessXEvent(int x, int y)
575 XEvent Event,event;
576 static int is_key_pressed = 0;
577 static int is_button_pressed = 0;
578 char buf[32];
579 static int ex=10000, ey=10000, ex2=0, ey2=0;
581 while (FPending(dpy))
583 FNextEvent(dpy,&Event);
584 switch(Event.type)
586 case Expose:
587 ex = min(ex, Event.xexpose.x);
588 ey = min(ey, Event.xexpose.y);
589 ex2 = max(ex2, Event.xexpose.x + Event.xexpose.width);
590 ey2=max(ey2 , Event.xexpose.y + Event.xexpose.height);
591 while (FCheckTypedEvent(dpy, Expose, &Event))
593 ex = min(ex, Event.xexpose.x);
594 ey = min(ey, Event.xexpose.y);
595 ex2 = max(
596 ex2,
597 Event.xexpose.x + Event.xexpose.width);
598 ey2=max(ey2,
599 Event.xexpose.y + Event.xexpose.height);
601 if (FftSupport && Ffont->fftf.fftfont != NULL)
603 XClearArea(
604 dpy, main_win,
605 ex, ey, ex2-ex, ey2-ey, False);
607 DrawItems(main_win, ex, ey, ex2-ex, ey2-ey);
608 ex = ey = 10000;
609 ex2 = ey2 = 0;
610 break;
611 case KeyPress:
612 is_key_pressed = 1;
613 break;
614 case ButtonPress:
615 is_button_pressed = Event.xbutton.button;
616 break;
617 case KeyRelease:
618 if (is_key_pressed)
620 exit(0);
622 break;
623 case ButtonRelease:
624 if (is_button_pressed)
626 if (is_button_pressed == 2 &&
627 Event.xbutton.button == 2)
629 /* select a new window when
630 * button 2 is pressed */
631 SetMessageMask(
632 fd, M_CONFIGURE_WINDOW |
633 M_WINDOW_NAME |
634 M_ICON_NAME |
635 M_RES_CLASS |
636 M_RES_NAME |
637 M_END_WINDOWLIST |
638 M_CONFIG_INFO |
639 M_END_CONFIG_INFO|
640 M_SENDCONFIG);
641 SendText(fd, "Send_WindowList", 0);
642 XDestroyWindow(dpy, main_win);
643 DestroyList();
644 fvwmlib_get_target_window(
645 dpy, screen, module->name,
646 &(module->window), True);
647 found = 0;
648 return 1;
650 else
652 exit(0);
655 break;
656 case ClientMessage:
657 if (Event.xclient.format==32 &&
658 Event.xclient.data.l[0]==wm_del_win)
660 exit(0);
662 break;
663 case ReparentNotify:
664 if (minimal_layer >= 0)
666 sprintf(buf, "Layer 0 %d", my_layer);
667 SendText(fd, buf, main_win);
669 SendText(fd, "Raise", main_win);
670 break;
671 case ConfigureNotify:
672 /* this only happens with transparent windows,
673 * slurp up as many events as possible before
674 * redrawing to reduce flickering */
675 while (FCheckTypedEvent(
676 dpy, ConfigureNotify, &event))
678 if (!event.xconfigure.send_event)
679 continue;
680 Event.xconfigure.x = event.xconfigure.x;
681 Event.xconfigure.y = event.xconfigure.y;
682 Event.xconfigure.send_event = True;
684 /* Only refresh if moved */
685 if ((Event.xconfigure.send_event ||
686 CSET_IS_TRANSPARENT_PR_PURE(colorset)) &&
687 (x != Event.xconfigure.x ||
688 y != Event.xconfigure.y))
690 static Bool is_initial_cn = True;
691 Bool do_eat_expose = False;
693 x = Event.xconfigure.x;
694 y = Event.xconfigure.y;
695 /* flush any expose events */
696 if (UsePixmapDrawing)
698 PixmapDrawWindow(
699 main_width, main_height);
700 do_eat_expose = True;
702 else if (colorset == -1)
704 do_eat_expose = True;
706 else if (UpdateBackgroundTransparency(
707 dpy, main_win, main_width,
708 main_height,
709 &Colorset[(colorset)], Pdepth,
710 gc, True) == True)
712 do_eat_expose = True;
714 if (do_eat_expose == True &&
715 is_initial_cn == False)
717 while (FCheckTypedEvent(
718 dpy, Expose, &Event))
720 /* nothing */
723 is_initial_cn = False;
725 break;
728 XFlush (dpy);
730 return 0;
735 * End of window list, open an x window and display data in it
738 void list_end(void)
740 XSizeHints mysizehints;
741 XGCValues gcv;
742 unsigned long gcm;
743 int lmax,height;
744 int x,y;
745 XSetWindowAttributes attributes;
747 if(!found)
749 exit(0);
752 /* tell fvwm to only send config messages */
753 SetMessageMask(fd, M_CONFIG_INFO | M_SENDCONFIG);
755 if ((Ffont = FlocaleLoadFont(dpy, font_string, module->name)) == NULL)
757 fprintf(
758 stderr,"%s: cannot load font, exiting\n",
759 module->name);
760 exit(1);
763 /* chose the rendering methode */
764 if (FftSupport && Ffont->fftf.fftfont != NULL)
766 UsePixmapDrawing = True;
768 /* make window infomation list */
769 MakeList();
771 /* size and create the window */
772 lmax = max_col1 + max_col2 + 15;
774 height = ListSize * (Ffont->height);
776 mysizehints.flags=
777 USSize|USPosition|PWinGravity|PResizeInc|PBaseSize|PMinSize|
778 PMaxSize;
779 main_width = mysizehints.width = lmax + 10;
780 main_height = mysizehints.height = height + 10;
781 mysizehints.width_inc = 1;
782 mysizehints.height_inc = 1;
783 mysizehints.base_height = mysizehints.height;
784 mysizehints.base_width = mysizehints.width;
785 mysizehints.min_height = mysizehints.height;
786 mysizehints.min_width = mysizehints.width;
787 mysizehints.max_height = mysizehints.height;
788 mysizehints.max_width = mysizehints.width;
789 mysizehints.win_gravity = NorthWestGravity;
791 int sx;
792 int sy;
793 int sw;
794 int sh;
795 Window JunkW;
796 int JunkC;
797 unsigned int JunkM;
798 fscreen_scr_arg fscr;
800 if (!FQueryPointer(
801 dpy, Root, &JunkW, &JunkW, &x, &y, &JunkC, &JunkC,
802 &JunkM))
804 /* pointer is on a different screen */
805 x = 0;
806 y = 0;
809 fscr.xypos.x = x;
810 fscr.xypos.y = y;
811 FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &sx, &sy, &sw, &sh);
812 if (y + height + 100 > sy + sh)
814 y = sy + sh - height - 10;
815 mysizehints.win_gravity = SouthWestGravity;
817 if (x + lmax + 100 > sx + sw)
819 x = sx + sw - lmax - 10;
820 if (mysizehints.win_gravity == SouthWestGravity)
821 mysizehints.win_gravity = SouthEastGravity;
822 else
823 mysizehints.win_gravity = NorthEastGravity;
827 if (Pdepth < 2)
829 back_pix = GetColor("white");
830 fore_pix = GetColor("black");
832 else
834 back_pix = (colorset < 0)?
835 GetColor(BackColor) : Colorset[colorset].bg;
836 fore_pix = (colorset < 0)?
837 GetColor(ForeColor) : Colorset[colorset].fg;
840 attributes.colormap = Pcmap;
841 attributes.border_pixel = 0;
842 attributes.background_pixel = back_pix;
843 main_win = XCreateWindow(
844 dpy, Root, x, y, mysizehints.width, mysizehints.height, 0,
845 Pdepth, InputOutput, Pvisual, CWColormap | CWBackPixel |
846 CWBorderPixel, &attributes);
847 wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
848 XSetWMProtocols(dpy,main_win,&wm_del_win,1);
850 /* hack to prevent mapping on wrong screen with StartsOnScreen */
851 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &mysizehints);
852 XSetWMNormalHints(dpy,main_win,&mysizehints);
853 /* have to ask for configure events when transparent */
854 if (CSET_IS_TRANSPARENT(colorset))
856 mw_events |= StructureNotifyMask;
857 if (CSET_IS_TRANSPARENT_PR_PURE(colorset))
859 UsePixmapDrawing = 0;
862 if (!UsePixmapDrawing)
864 mw_events |= ExposureMask;
867 XSelectInput(dpy, main_win, mw_events);
868 change_window_name(module->name);
870 gcm = GCForeground;
871 gcv.foreground = fore_pix;
872 if (Ffont->font != NULL)
874 gcm |= GCFont;
875 gcv.font = Ffont->font->fid;
877 gc = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
878 if (UsePixmapDrawing)
880 PixmapDrawWindow(main_width, main_height);
882 else if (colorset >= 0)
884 SetWindowBackground(
885 dpy, main_win, main_width, main_height,
886 &Colorset[(colorset)], Pdepth, gc, True);
888 XMapWindow(dpy,main_win);
890 /* Window is created. Display it until the user clicks or deletes it.
891 * also grok any dynamic config changes */
892 while(1)
894 FvwmPacket* packet;
895 int x_fd = XConnectionNumber(dpy);
896 fd_set fdset;
898 FD_ZERO(&fdset);
899 FD_SET(fd[1], &fdset);
900 FD_SET(x_fd, &fdset);
902 /* process all X events first */
903 if (ProcessXEvent(x,y) == 1)
905 return;
908 /* wait for X-event or config line */
909 select(fd_width, SELECT_FD_SET_CAST &fdset, NULL, NULL, NULL );
911 /* parse any dynamic config lines */
912 if (FD_ISSET(fd[1], &fdset))
914 packet = ReadFvwmPacket(fd[1]);
915 if (packet == NULL)
916 exit(0);
917 if (packet && packet->type == MX_PROPERTY_CHANGE)
919 list_property_change(packet->body);
921 if (packet && packet->type == M_CONFIG_INFO)
923 list_config_info(packet->body);
931 * Draw the items
934 void DrawItems(Drawable d, int x, int y, int w, int h)
936 int fontheight,i=0;
937 struct Item *cur = itemlistRoot;
938 Region region = 0;
940 fontheight = Ffont->height;
941 FwinString->win = d;
942 FwinString->gc = gc;
943 FwinString->flags.has_clip_region = False;
944 if (w > 0)
946 XRectangle r;
948 r.x = x;
949 r.y = y;
950 r.width = w;
951 r.height = h;
953 region = XCreateRegion();
954 XUnionRectWithRegion(&r, region, region);
955 XSetRegion(dpy, gc, region);
956 FwinString->flags.has_clip_region = True;
957 FwinString->clip_region = region;
960 if (colorset >= 0)
962 FwinString->colorset = &Colorset[colorset];
963 FwinString->flags.has_colorset = True;
965 while(cur != NULL) /* may be optimised */
967 /* first column */
968 FwinString->str = cur->col1;
969 FwinString->x = 5;
970 FwinString->y = 5 + Ffont->ascent + i * fontheight;
971 FlocaleDrawString(dpy, Ffont, FwinString, 0);
973 /* second column */
974 FwinString->str = cur->col2;
975 FwinString->x = 10 + max_col1;
976 FlocaleDrawString(dpy, Ffont, FwinString, 0);
978 ++i;
979 cur = cur->next;
981 if (FwinString->flags.has_clip_region)
983 XDestroyRegion(region);
984 XSetClipMask(dpy, gc, None);
986 XFlush (dpy);
989 void PixmapDrawWindow(int w, int h)
991 Pixmap pix;
992 XGCValues gcv;
993 unsigned long gcm;
995 if (colorset >= 0)
997 Pixmap cs_pix;
998 cs_pix = CreateBackgroundPixmap(dpy, main_win, w, h,
999 &Colorset[(colorset)],
1000 Pdepth, gc, False);
1001 if (cs_pix == ParentRelative)
1003 pix = cs_pix;
1005 else
1007 pix = CreateTiledPixmap(
1008 dpy, cs_pix, 0,0,w,h,Pdepth, gc);
1009 XFreePixmap(dpy, cs_pix);
1012 else
1014 gcm = GCForeground;
1015 gcv.foreground = back_pix;
1016 XChangeGC(dpy, gc, gcm, &gcv);
1017 pix = XCreatePixmap(dpy, main_win, w, h, Pdepth);
1018 XFillRectangle(dpy, pix, gc, 0, 0, w, h);
1019 gcv.foreground = fore_pix;
1020 XChangeGC(dpy, gc, gcm, &gcv);
1023 if (pix != ParentRelative)
1025 DrawItems(pix, 0, 0, 0, 0);
1026 XSetWindowBackgroundPixmap(dpy, main_win, pix);
1027 XClearWindow(dpy, main_win);
1028 XFreePixmap(dpy, pix);
1030 else
1032 XSetWindowBackgroundPixmap(dpy, main_win, pix);
1033 XClearWindow(dpy, main_win);
1034 DrawItems(main_win, 0, 0, 0, 0);
1039 * Change the window name displayed in the title bar.
1041 void change_window_name(char *str)
1043 XTextProperty name;
1044 XClassHint myclasshints;
1046 if (XStringListToTextProperty(&str,1,&name) == 0)
1048 fprintf(stderr,"%s: cannot allocate window name",module->name);
1049 return;
1051 XSetWMName(dpy,main_win,&name);
1052 XSetWMIconName(dpy,main_win,&name);
1053 XFree(name.value);
1054 myclasshints.res_name = str;
1055 myclasshints.res_class = "FvwmIdent";
1056 XSetClassHint(dpy,main_win,&myclasshints);
1060 void DestroyList(void)
1062 struct Item *t;
1063 struct Item *tmp;
1065 for (t = itemlistRoot; t; t = tmp)
1067 tmp = t->next;
1068 free(t);
1070 itemlistRoot = NULL;
1075 * Add s1(string at first column) and s2(string at second column) to itemlist
1078 void AddToList(char *s1, char* s2)
1080 int tw1, tw2;
1081 struct Item* item, *cur = itemlistRoot;
1083 tw1 = FlocaleTextWidth(Ffont, s1, strlen(s1));
1084 tw2 = FlocaleTextWidth(Ffont, s2, strlen(s2));
1085 max_col1 = max_col1 > tw1 ? max_col1 : tw1;
1086 max_col2 = max_col2 > tw2 ? max_col2 : tw2;
1088 item = (struct Item*)safemalloc(sizeof(struct Item));
1090 item->col1 = s1;
1091 item->col2 = s2;
1092 item->next = NULL;
1094 if (cur == NULL)
1096 itemlistRoot = item;
1098 else
1100 while(cur->next != NULL)
1102 cur = cur->next;
1104 cur->next = item;
1106 ListSize++;
1109 void MakeList(void)
1111 int bw,width,height,x1,y1,x2,y2;
1112 char loc[20];
1113 static char xstr[6],ystr[6];
1114 /* GSFR - quick hack because the new macros depend on a prt reference
1116 struct target_struct *targ = &target;
1118 ListSize = 0;
1120 bw = 2*target.border_w;
1121 width = target.frame_w - bw;
1122 height = target.frame_h - bw;
1123 if (target.title_dir == DIR_W || target.title_dir == DIR_E)
1125 width -= target.title_h;
1127 else if (target.title_dir == DIR_N || target.title_dir == DIR_S)
1129 height -= target.title_h;
1132 sprintf(desktop, "%ld", target.desktop);
1133 sprintf(layer, "%ld", target.layer);
1134 sprintf(id, "0x%x", (unsigned int)target.id);
1135 sprintf(swidth, "%d", width);
1136 sprintf(sheight, "%d", height);
1137 sprintf(borderw, "%ld", target.border_w);
1138 sprintf(xstr, "%ld", target.frame_x);
1139 sprintf(ystr, "%ld", target.frame_y);
1141 AddToList("Name:", target.name);
1142 AddToList("Icon Name:", target.icon_name);
1143 AddToList("Class:", target.class);
1144 AddToList("Resource:", target.res);
1145 AddToList("Window ID:", id);
1146 AddToList("Desk:", desktop);
1147 AddToList("Layer:", layer);
1148 AddToList("Width:", swidth);
1149 AddToList("Height:", sheight);
1150 AddToList("X (current page):", xstr);
1151 AddToList("Y (current page):", ystr);
1152 AddToList("Boundary Width:", borderw);
1154 AddToList("StickyPage:", (IS_STICKY_ACROSS_PAGES(targ) ? yes : no));
1155 AddToList("StickyDesk:", (IS_STICKY_ACROSS_DESKS(targ) ? yes : no));
1156 AddToList("StickyPageIcon:",
1157 (IS_ICON_STICKY_ACROSS_PAGES(targ) ? yes : no));
1158 AddToList("StickyDeskIcon:",
1159 (IS_ICON_STICKY_ACROSS_DESKS(targ) ? yes : no));
1160 AddToList("NoTitle:", (HAS_TITLE(targ) ? no : yes));
1161 AddToList("Iconified:", (IS_ICONIFIED(targ) ? yes : no));
1162 AddToList("Transient:", (IS_TRANSIENT(targ) ? yes : no));
1163 AddToList("WindowListSkip:", (DO_SKIP_WINDOW_LIST(targ) ? yes : no));
1165 switch(target.gravity)
1167 case ForgetGravity:
1168 AddToList("Gravity:", "Forget");
1169 break;
1170 case NorthWestGravity:
1171 AddToList("Gravity:", "NorthWest");
1172 break;
1173 case NorthGravity:
1174 AddToList("Gravity:", "North");
1175 break;
1176 case NorthEastGravity:
1177 AddToList("Gravity:", "NorthEast");
1178 break;
1179 case WestGravity:
1180 AddToList("Gravity:", "West");
1181 break;
1182 case CenterGravity:
1183 AddToList("Gravity:", "Center");
1184 break;
1185 case EastGravity:
1186 AddToList("Gravity:", "East");
1187 break;
1188 case SouthWestGravity:
1189 AddToList("Gravity:", "SouthWest");
1190 break;
1191 case SouthGravity:
1192 AddToList("Gravity:", "South");
1193 break;
1194 case SouthEastGravity:
1195 AddToList("Gravity:", "SouthEast");
1196 break;
1197 case StaticGravity:
1198 AddToList("Gravity:", "Static");
1199 break;
1200 default:
1201 AddToList("Gravity:", "Unknown");
1202 break;
1204 x1 = target.frame_x;
1205 if(x1 < 0)
1207 x1 = 0;
1209 x2 = DisplayWidth(dpy,screen) - x1 - target.frame_w;
1210 if(x2 < 0)
1212 x2 = 0;
1214 y1 = target.frame_y;
1215 if(y1 < 0)
1217 y1 = 0;
1219 y2 = DisplayHeight(dpy,screen) - y1 - target.frame_h;
1220 if(y2 < 0)
1222 y2 = 0;
1224 width = (width - target.base_w)/target.width_inc;
1225 height = (height - target.base_h)/target.height_inc;
1227 sprintf(loc,"%dx%d",width,height);
1228 strcpy(geometry, loc);
1230 if ((target.gravity == EastGravity) ||
1231 (target.gravity == NorthEastGravity)||
1232 (target.gravity == SouthEastGravity))
1234 sprintf(loc,"-%d",x2);
1236 else
1238 sprintf(loc,"+%d",x1);
1240 strcat(geometry, loc);
1242 if((target.gravity == SouthGravity)||
1243 (target.gravity == SouthEastGravity)||
1244 (target.gravity == SouthWestGravity))
1246 sprintf(loc,"-%d",y2);
1248 else
1250 sprintf(loc,"+%d",y1);
1252 strcat(geometry, loc);
1253 AddToList("Geometry:", geometry);
1256 Atom *protocols = NULL, *ap;
1257 Atom _XA_WM_TAKE_FOCUS = XInternAtom(
1258 dpy, "WM_TAKE_FOCUS", False);
1259 XWMHints *wmhintsp = XGetWMHints(dpy,target.id);
1260 int i,n;
1261 Boolean HasTakeFocus=False,InputField=True;
1262 char *focus_policy="",*ifstr="",*tfstr="";
1264 if (wmhintsp)
1266 InputField=wmhintsp->input;
1267 ifstr=InputField?"True":"False";
1268 XFree(wmhintsp);
1270 else
1272 ifstr="XWMHints missing";
1274 if (XGetWMProtocols(dpy,target.id,&protocols,&n))
1276 for (i = 0, ap = protocols; i < n; i++, ap++)
1278 if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
1279 HasTakeFocus = True;
1281 tfstr=HasTakeFocus?"Present":"Absent";
1282 XFree(protocols);
1284 else
1286 tfstr="XGetWMProtocols failed";
1288 if (HasTakeFocus)
1290 if (InputField)
1292 focus_policy = "Locally Active";
1294 else
1296 focus_policy = "Globally Active";
1299 else
1301 if (InputField)
1303 focus_policy = "Passive";
1305 else
1307 focus_policy = "No Input";
1310 AddToList("Focus Policy:",focus_policy);
1311 AddToList(" - Input Field:",ifstr);
1312 AddToList(" - WM_TAKE_FOCUS:",tfstr);
1314 /* flags hints that were supplied */
1315 long supplied_return;
1316 int getrc;
1317 XSizeHints *size_hints =
1318 XAllocSizeHints(); /* the size hints */
1319 if ((getrc = XGetWMSizeHints(
1320 dpy,target.id, /* get size hints */
1321 size_hints, /* Hints */
1322 &supplied_return,
1323 XA_WM_ZOOM_HINTS)))
1325 if (supplied_return & PAspect)
1326 { /* if window has a aspect ratio */
1327 sprintf(
1328 mymin_aspect, "%d/%d",
1329 size_hints->min_aspect.x,
1330 size_hints->min_aspect.y);
1331 AddToList(
1332 "Minimum aspect ratio:",
1333 mymin_aspect);
1334 sprintf(
1335 max_aspect, "%d/%d",
1336 size_hints->max_aspect.x,
1337 size_hints->max_aspect.y);
1338 AddToList(
1339 "Maximum aspect ratio:",
1340 max_aspect);
1341 } /* end aspect ratio */
1342 XFree(size_hints);
1343 } /* end getsizehints worked */
1347 /* EWMH window type */
1348 if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DESKTOP_ID)
1349 AddToList("EWMH Window Type:","Desktop");
1350 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DIALOG_ID)
1351 AddToList("EWMH Window Type:","Dialog");
1352 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DOCK_ID)
1353 AddToList("EWMH Window Type:","Dock");
1354 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_MENU_ID)
1355 AddToList("EWMH Window Type:","Menu");
1356 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_NORMAL_ID)
1357 AddToList("EWMH Window Type:","Normal");
1358 else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_TOOLBAR_ID)
1359 AddToList("EWMH Window Type:","ToolBar");
1361 /* EWMH wm state */
1362 ewmh_init_state[0] = '\0';
1363 if (HAS_EWMH_INIT_FULLSCREEN_STATE(targ) == EWMH_STATE_HAS_HINT)
1365 strcat(ewmh_init_state, "FullScreen ");
1367 if (HAS_EWMH_INIT_HIDDEN_STATE(targ) == EWMH_STATE_HAS_HINT)
1369 strcat(ewmh_init_state, "Iconic ");
1371 if (HAS_EWMH_INIT_MAXHORIZ_STATE(targ) == EWMH_STATE_HAS_HINT)
1373 strcat(ewmh_init_state, "MaxHoriz ");
1375 if (HAS_EWMH_INIT_MAXVERT_STATE(targ) == EWMH_STATE_HAS_HINT)
1377 strcat(ewmh_init_state, "MaxVert ");
1379 if (HAS_EWMH_INIT_MODAL_STATE(targ) == EWMH_STATE_HAS_HINT)
1381 strcat(ewmh_init_state, "Modal ");
1383 if (HAS_EWMH_INIT_SHADED_STATE(targ)== EWMH_STATE_HAS_HINT)
1385 strcat(ewmh_init_state, "Shaded ");
1387 if (HAS_EWMH_INIT_SKIP_PAGER_STATE(targ) == EWMH_STATE_HAS_HINT ||
1388 HAS_EWMH_INIT_SKIP_TASKBAR_STATE(targ) == EWMH_STATE_HAS_HINT )
1390 strcat(ewmh_init_state, "SkipList ");
1392 if (HAS_EWMH_INIT_STICKY_STATE(targ) == EWMH_STATE_HAS_HINT ||
1393 (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT &&
1394 (target.ewmh_hint_desktop == (unsigned long)-2 ||
1395 target.ewmh_hint_desktop == (unsigned long)-1)))
1397 strcat(ewmh_init_state, "Sticky ");
1399 /* FIXME: we should use the fvwm default layers */
1400 if (target.ewmh_hint_layer == 6)
1402 strcat(ewmh_init_state, "StaysOnTop ");
1404 else if (target.ewmh_hint_layer == 2)
1406 strcat(ewmh_init_state, "StaysOnBottom ");
1408 if (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT &&
1409 target.ewmh_hint_desktop < 256)
1411 strcat(ewmh_init_state, "StartOnDesk");
1412 sprintf(ewmh_init_state, "%s %lu ",
1413 ewmh_init_state, target.ewmh_hint_desktop);
1415 if (ewmh_init_state[0] != '\0')
1417 /* remove ending space */
1418 ewmh_init_state[strlen(ewmh_init_state)-1] = '\0';
1419 AddToList("EWMH Init State:",ewmh_init_state);
1424 X Error Handler
1426 static int
1427 ErrorHandler(Display *d, XErrorEvent *event)
1429 #if 0
1430 if (event->error_code == BadPixmap)
1432 return 0;
1434 if (event->error_code == BadDrawable)
1436 return 0;
1438 if (event->error_code == FRenderGetErrorCodeBase() + FRenderBadPicture)
1440 return 0;
1442 #endif
1444 PrintXErrorAndCoredump(d, event, module->name);
1445 return 0;