/* -*-c-*- */ /* FvwmTaskBar Module for Fvwm. * * (Much reworked version of FvwmWinList) * Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or * Mike_Finger@atk.com) * * Two little hacks by DYB: 1) make size of a strip in hidden state tunable * (with *FvwmTaskBar: AutoHide ); 2) make process of TaskBar * hiding/unhiding more smooth. * * Minor hack by TKP to enable autohide to work with pages (leaves 2 pixels * visible so that the 1 pixel panframes don't get in the way) * * Merciless hack by RBW for the Great Style Flag Rewrite - 04/20/1999. * Now the GSFR is used and there are no other flags (olicha may 19, 2000). * * The author makes not guarantees or warantees, either express or * implied. Feel free to use any code contained here for any purpose, as long * and this and any other applicable copyrights are kept intact. * The functions in this source file that are based on part of the FvwmIdent * module for Fvwm are noted by a small copyright atop that function, all others * are copyrighted by Mike Finger. For those functions modified/used, here is * the full, original copyright: * * Copyright 1994, Robert Nation and Nobutaka Suzuki. * No guarantees or warantees or anything * are provided or implied in any way whatsoever. Use this program at your * own risk. Permission to use this program for any purpose is given, * as long as the copyright is kept intact. */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include "libs/ftime.h" #include #include #include #include #include #ifdef HAVE_SYS_BSDTYPES_H #include /* Saul */ #endif /* Saul */ #include "libs/Module.h" #include "libs/fvwmlib.h" /* for pixmaps routines */ #include "libs/FScreen.h" #include "libs/FShape.h" #include "libs/fvwmsignal.h" #include "libs/Colorset.h" #include "libs/Flocale.h" #include "libs/gravity.h" #include "libs/FRender.h" #include "libs/FRenderInit.h" #include "libs/FGettext.h" #include "libs/ColorUtils.h" #include "libs/Graphics.h" #include "libs/Parse.h" #include "libs/Strings.h" #include "libs/XError.h" #include "FvwmTaskBar.h" #include "ButtonArray.h" #include "List.h" #include "Mallocs.h" #include "Goodies.h" #include "Start.h" #define MAX_NO_ICON_ACTION_LENGTH (MAX_MODULE_INPUT_TEXT_LEN - 100) #define GRAB_EVENTS (ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|EnterWindowMask|LeaveWindowMask) #define SomeButtonDown(a) ((a) & DEFAULT_ALL_BUTTONS_MASK) #define DEFAULT_CLICK1 "Iconify -1, Raise, Focus" #define DEFAULT_CLICK2 "Iconify +1, Lower" #define DEFAULT_CLICK3 "Nop" #define DEFAULT_CLICK_N "Nop" #define gray_width 8 #define gray_height 8 unsigned char gray_bits[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }; #define DEFAULT_VISIBLE_PIXELS 3 /* File type information */ int Fvwm_fd[2]; int x_fd; /* X related things */ Display *dpy; Window Root, win; int screen; Pixel back; Pixel fore; static Pixel iconfore; static Pixel iconback; static Pixel focusfore; static Pixel focusback; GC icongraph = None; GC iconbackgraph = None; GC focusgraph = None; GC focusbackgraph = None; GC graph = None; GC shadow = None; GC hilite = None; GC iconshadow = None; GC iconhilite = None; GC focusshadow = None; GC focushilite = None; GC blackgc = None; GC whitegc = None; GC checkered = None; int pad = 3; int colorset = -1; int iconcolorset = -1; int focuscolorset = -1; FlocaleFont *FButtonFont, *FSelButtonFont; FlocaleWinString *FwinString; int fontheight; static Atom wm_del_win; Atom MwmAtom = None; static Bool is_dead_pipe = False; /* Module related information */ ModuleArgs *module; int win_width = 5, win_height = 5, win_grav, win_x, win_y, win_border = 4, win_has_title = 0, win_title_dir = 0, win_title_height = 0, win_is_shaded = 0, button_width = DEFAULT_BTN_WIDTH, ButPressed = -1, ButReleased = -1, Checked = 0, WindowState = -2, /* -2 unmaped, 1 not hidden, -1 hidden, * 0 hidden -> not hidden (for the events loop) */ FocusInWin = 0; /* 1 if the Taskbar has the focus */ direction_t win_shade_direction = 0; static int auto_stick_y = 0; static volatile sig_atomic_t AlarmSet = NOT_SET; static volatile sig_atomic_t tip_window_alarm = False; static volatile sig_atomic_t hide_taskbar_alarm = False; static volatile sig_atomic_t stick_taskbar_alarm = False; int UpdateInterval = 30; int whichButton = -1; Bool startButtonPressed = False; ButtonArray buttons; List windows; char *ClickAction[max(NUMBER_OF_EXTENDED_MOUSE_BUTTONS, 3)] = { DEFAULT_CLICK1, DEFAULT_CLICK2, DEFAULT_CLICK3 }, *EnterAction, *BackColor = "white", *ForeColor = "black", *IconBackColor = "white", *IconForeColor = "black", *FocusBackColor = NULL, *FocusForeColor = NULL, *geometry = NULL, *font_string = NULL, *selfont_string = NULL; static char *AnimCommand = NULL; int UseSkipList = False, UseIconNames = False, ShowTransients = False, adjust_flag = False, AutoStick = False, AutoHide = False, AutoFocus = False, HighlightFocus = False, DeskOnly = False, PageOnly = False, ScreenOnly = False, NoBrightFocus = False, ThreeDfvwm = False, RowsNumber = 1; int VisiblePixels = DEFAULT_VISIBLE_PIXELS; /* This macro should be used when calculating geometry */ #define VISIBLE_PIXELS() (VisiblePixels < win_height? VisiblePixels:win_height) rectangle screen_g; rectangle global_scr_g; int NRows, RowHeight, Midline; int ButtonPressed; #define COUNT_LIMIT 10000 long DeskNumber; /* Added by Balaji R */ int First = 1; int Count = 0; /* Imported from Goodies */ extern int stwin_width, goodies_width, goodies_fontheight; extern TipStruct Tip; /* Imported from Start */ extern int StartAndLaunchButtonsWidth, StartAndLaunchButtonsHeight; extern StartAndLaunchButtonItem *First_Start_Button; extern StartAndLaunchButtonItem *Last_Start_Button; extern int WindowButtonsLeftMargin; extern int WindowButtonsRightMargin; char *ImagePath = NULL; char *XineramaConfig = NULL; static int fscreen = 0; static void ParseConfig( void ); static void ParseConfigLine(char *tline); static void ShutMeDown(void); static RETSIGTYPE TerminateHandler(int sig); static RETSIGTYPE Alarm(int sig); static void SetAlarm(tb_alarm_t event); static void ClearAlarm(tb_alarm_t event); static void DoAlarmAction(void); static int ErrorHandler(Display*, XErrorEvent*); static Bool change_colorset(int cset, Bool force); static void WarpTaskBar(int y); int IsItemIndexIconSuppressed(List *list, int i); /* Main - Setup the XConnection,request the window list and loop forever Based on main() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ int main(int argc, char **argv) { int i; FlocaleInit(LC_CTYPE, "", "", "FvwmTaskBar"); setlocale(LC_TIME, ""); FGettextInit("FvwmTaskBar", LOCALEDIR, "FvwmTaskBar"); for (i = 3; i < NUMBER_OF_EXTENDED_MOUSE_BUTTONS; i++) { ClickAction[i] = DEFAULT_CLICK_N; } module = ParseModuleArgs(argc,argv,1); /* use alias if provided */ if (module==NULL) { fprintf(stderr, "FvwmTaskBar Version %s should only be executed by fvwm!\n", VERSION); exit(1); } /* setup fvwm pipes */ Fvwm_fd[0] = module->to_fvwm; Fvwm_fd[1] = module->from_fvwm; #ifdef HAVE_SIGACTION { struct sigaction sigact; sigemptyset(&sigact.sa_mask); #ifdef SA_RESTART sigact.sa_flags = SA_RESTART; #else sigact.sa_flags = 0; #endif sigact.sa_handler = Alarm; sigaction(SIGALRM, &sigact, NULL); #ifdef SA_INTERRUPT sigact.sa_flags = SA_INTERRUPT; #else sigact.sa_flags = 0; #endif sigaddset(&sigact.sa_mask, SIGPIPE); sigaddset(&sigact.sa_mask, SIGTERM); sigaddset(&sigact.sa_mask, SIGINT); sigact.sa_handler = TerminateHandler; sigaction(SIGPIPE, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); } #else #ifdef USE_BSD_SIGNALS fvwmSetSignalMask( sigmask(SIGTERM) | sigmask(SIGPIPE) | sigmask(SIGINT) ); #endif signal (SIGPIPE, TerminateHandler); signal (SIGTERM, TerminateHandler); signal (SIGINT, TerminateHandler); signal (SIGALRM, Alarm); #ifdef HAVE_SIGINTERRUPT siginterrupt(SIGPIPE, 1); siginterrupt(SIGTERM, 1); siginterrupt(SIGINT, 1); #endif #endif SetMessageMask(Fvwm_fd,M_ADD_WINDOW | M_CONFIGURE_WINDOW | M_DESTROY_WINDOW | M_VISIBLE_NAME | M_RES_NAME | M_DEICONIFY | M_ICONIFY | M_END_WINDOWLIST | M_FOCUS_CHANGE | M_CONFIG_INFO | M_END_CONFIG_INFO | M_NEW_DESK | M_SENDCONFIG | M_MINI_ICON ); /* extended messages */ SetMessageMask(Fvwm_fd, MX_VISIBLE_ICON_NAME | MX_PROPERTY_CHANGE); /* Parse the config file */ ParseConfig(); /* Setup the XConnection */ StartMeUp(); XSetErrorHandler(ErrorHandler); StartButtonInit(RowHeight); /* init the array of buttons */ InitArray(&buttons, StartAndLaunchButtonsWidth + WindowButtonsLeftMargin, 0, win_width - stwin_width - StartAndLaunchButtonsWidth - WindowButtonsLeftMargin - WindowButtonsRightMargin, RowHeight, button_width); InitList(&windows); /* Request a list of all windows, * wait for ConfigureWindow packets */ SendText(Fvwm_fd, "Send_WindowList",0); /* tell fvwm we're running */ SendFinishedStartupNotification(Fvwm_fd); /* Lock on send only for iconify and deiconify (for NoIconAction) */ if (AnimCommand && (AnimCommand[0] != 0)) { SetSyncMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY); SetNoGrabMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY); } /* Receive all messages from Fvwm */ EndLessLoop(); #ifdef FVWM_DEBUG_MSGS if ( isTerminated ) { fprintf(stderr, "%s: Received signal: exiting...\n", module->name); } #endif return 0; } /* EndLessLoop - Read and redraw until we get killed, blocking when can't read */ void EndLessLoop(void) { fd_set readset; fd_set_size_t fd_width; struct timeval tv; fd_width = x_fd; if (Fvwm_fd[1] > fd_width) fd_width = Fvwm_fd[1]; ++fd_width; while ( !isTerminated ) { FD_ZERO(&readset); FD_SET(Fvwm_fd[1], &readset); FD_SET(x_fd, &readset); tv.tv_sec = UpdateInterval; tv.tv_usec = 0; XFlush(dpy); if ( fvwmSelect(fd_width, &readset, NULL, NULL, &tv) > 0 ) { if (FD_ISSET(x_fd, &readset) || FPending(dpy)) LoopOnEvents(); if (FD_ISSET(Fvwm_fd[1], &readset)) { ReadFvwmPipe(); } } DoAlarmAction(); DrawGoodies(NULL); } /* while */ } /* ReadFvwmPipe - Read a single message from the pipe from Fvwm Originally Loop() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ReadFvwmPipe(void) { FvwmPacket* packet = ReadFvwmPacket(Fvwm_fd[1]); if ( packet == NULL ) DeadPipe(0); else ProcessMessage( packet->type, packet->body ); } /* ProcessMessage - Process the message coming from Fvwm Skeleton based on processmessage() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ProcessMessage(unsigned long type,unsigned long *body) { int redraw=-1; int i = -1; char *string; long Desk; FvwmPicture p; struct ConfigWinPacket *cfgpacket; int iconified; rectangle new_g; switch(type) { case M_FOCUS_CHANGE: i = FindItem(&windows, body[0]); if (win != body[0]) { /* This case is handled in LoopOnEvents() */ if (IsItemIconified(&windows, body[0])) i = -1; RadioButton(&buttons, i, BUTTON_BRIGHT); ButPressed = i; ButReleased = -1; redraw = 0; FocusInWin = 0; } else FocusInWin = 1; break; case M_ADD_WINDOW: case M_CONFIGURE_WINDOW: cfgpacket = (ConfigWinPacket *) body; new_g.x = cfgpacket->frame_x; new_g.y = cfgpacket->frame_y; new_g.width = cfgpacket->frame_width; new_g.height = cfgpacket->frame_height; if (!ShowTransients && (IS_TRANSIENT(cfgpacket))) break; /* Notes: users cannot modify the win_width of the taskbar (see the hints in StartMeUp; it is a good idea). So "we have to" modify the win_width here by modifying the WMNormalHints. Moreover, 1. we want that the TaskBar width with its border is execately the screen width 2. be carful with dynamic style change */ if (cfgpacket->w == win) { int nb; int nh; int nw; int ntd; int nht; int nth; nb = (short)cfgpacket->border_width; nw = screen_g.width - (nb<<1); nh = (int)cfgpacket->frame_height - (nb<<1); nht = HAS_TITLE(cfgpacket); ntd = GET_TITLE_DIR(cfgpacket); nth = (int)cfgpacket->title_height; if (ntd == DIR_S || ntd == DIR_N) { nh -= nth; } else { nw -= nth; } if (nb != win_border || nw != win_width || nh != win_height || nht != win_has_title || ntd != win_title_dir || nth != win_title_height) { XSizeHints hints; long dumy; win_border = nb; win_width = nw; win_has_title = nht; win_title_dir = ntd; win_title_height = nth; if (AutoStick) { win_x = screen_g.x + win_border; if (!win_is_shaded) { if (win_y > Midline) { win_y = screen_g.height - (AutoHide ? VISIBLE_PIXELS() - win_title_height * HAS_TITLE_DIR(cfgpacket, DIR_S) : win_height + win_border); } else { win_y = AutoHide ? VISIBLE_PIXELS() + win_title_height * HAS_TITLE_DIR(cfgpacket, DIR_S) - win_height : win_border + win_title_height; } } else { if (win_y > Midline) { win_y = screen_g.height - win_border - HAS_TITLE_DIR(cfgpacket, DIR_S) * win_height; } else { win_y = win_title_height + win_border - HAS_TITLE_DIR(cfgpacket, DIR_S) * win_height; } } win_y += screen_g.y; } XGetWMNormalHints(dpy,win,&hints,&dumy); hints.min_width = win_width; hints.base_width = win_width; hints.max_width = win_width; /* hack to prevent mapping on wrong screen with StartsOnScreen */ FScreenMangleScreenIntoUSPosHints(fscreen, &hints); XSetWMNormalHints(dpy,win,&hints); if (AutoStick) { XMoveResizeWindow(dpy, win, win_x, win_y, win_width, win_height); } else if (!IS_SHADED(cfgpacket)) { XResizeWindow(dpy, win, win_width, win_height); } UpdateArray(&buttons, -1, -1, win_width - stwin_width - StartAndLaunchButtonsWidth - WindowButtonsLeftMargin - WindowButtonsRightMargin, -1, -1); ArrangeButtonArray (&buttons); AdjustWindow(win_width, win_height); redraw = 1; } if (AutoStick && win_is_shaded != IS_SHADED(cfgpacket)) { win_is_shaded = IS_SHADED(cfgpacket); if (win_is_shaded) { if (win_y > Midline) { win_y = screen_g.height - win_border - (win_title_dir == DIR_S) * win_height; } else { win_y = win_title_height + win_border - (win_title_dir == DIR_S) * win_height; } } else { if (win_y > Midline) { win_y = screen_g.height - win_border - win_height; } else { win_y = win_title_height + win_border; } if (AutoHide) { WindowState = 1; SetAlarm(HIDE_TASK_BAR); } } win_y += screen_g.y; XMoveWindow(dpy, win, win_x, win_y); } win_is_shaded = IS_SHADED(cfgpacket); win_shade_direction = SHADED_DIR(cfgpacket); break; } if ((i=FindItem(&windows, body[0])) != -1) { int remove=0; int add = 0; int skiplist = 0; rectangle *pold_g; Bool is_on_desk = True; Bool is_changing_desk = False; Bool is_on_page = True; Bool is_changing_page = False; Bool is_on_screen = True; Bool is_changing_screen = False; Bool is_managed; if (!GetItemGeometry(&windows, i, &pold_g)) { pold_g = &new_g; } if (DeskOnly && GetDeskNumber(&windows,i,&Desk)) { if (IsItemIndexSticky(&windows,i)) { is_on_desk = True; is_changing_desk = False; } else { is_on_desk = (DeskNumber == cfgpacket->desk); is_changing_desk = (Desk != cfgpacket->desk); } UpdateItemIndexDesk(&windows, i, cfgpacket->desk); } if (PageOnly) { is_on_page = fvwmrect_do_rectangles_intersect(&new_g, &global_scr_g); is_changing_page = (fvwmrect_do_rectangles_intersect(pold_g, &global_scr_g) != is_on_page); } if (ScreenOnly) { is_on_screen = fvwmrect_do_rectangles_intersect(&new_g, &screen_g); is_changing_screen = (fvwmrect_do_rectangles_intersect(pold_g, &screen_g) != is_on_screen); } UpdateItemIndexGeometry(&windows, i, &new_g); is_managed = (is_on_desk && is_on_page && is_on_screen); if (is_changing_desk || is_changing_page || is_changing_screen) { if (is_managed) { /* window entering managed area of the virtual desktop */ add = 1; } else { /* window leaving managed area of the virtual desktop */ remove = 1; } } if (UseSkipList && is_managed) { skiplist = IsItemIndexSkipWindowList(&windows,i); if (DO_SKIP_WINDOW_LIST(cfgpacket) && !skiplist) { add = 0; remove = 1; } if (!DO_SKIP_WINDOW_LIST(cfgpacket) && skiplist) { add = 1; remove = 0; } } UpdateItemGSFRFlags(&windows, cfgpacket); if (remove) { RemoveButton(&buttons, i); redraw = 1; } else if (add) { AddButton(&buttons, ItemName(&windows,i), GetItemPicture(&windows,i), BUTTON_UP, i, IsItemIndexIconified(&windows, i)); redraw = 1; } } else if (!UseSkipList || !DO_SKIP_WINDOW_LIST(cfgpacket)) { AddItem(&windows, cfgpacket->w, cfgpacket, cfgpacket->desk, Count++); if (Count > COUNT_LIMIT) Count = 0; i = FindItem(&windows, cfgpacket->w); UpdateItemIndexGeometry(&windows, i, &new_g); } if (i != -1) { Button *temp = find_n(&buttons, i); if (temp && IS_ICONIFIED(cfgpacket)) temp->iconified = 1; } break; case M_DESTROY_WINDOW: if ((i = FindItem(&windows, body[0])) == -1) break; DeleteItem(&windows, body[0]); RemoveButton(&buttons, i); redraw = 1; break; case M_MINI_ICON: if (!FMiniIconsSupported || (i = FindItem(&windows, body[0])) == -1) break; { MiniIconPacket *mip = (MiniIconPacket *) body; p.picture = mip->picture; p.mask = mip->mask; p.alpha = mip->alpha; p.width = mip->width; p.height = mip->height; p.depth = mip->depth; } UpdateItemPicture(&windows, i, &p); if (UpdateButton(&buttons, i, NULL, DONT_CARE) != -1) { UpdateButtonPicture(&buttons, i, &p); redraw = 0; } break; case M_VISIBLE_NAME: case MX_VISIBLE_ICON_NAME: if ((type == MX_VISIBLE_ICON_NAME && !UseIconNames) || (type == M_VISIBLE_NAME && UseIconNames)) break; string = (char *) &body[3]; if ((i = UpdateItemName(&windows, body[0], (char *)&body[3])) == -1) break; if (UpdateButton(&buttons, i, string, DONT_CARE) == -1) { rectangle *pold_g; if (GetDeskNumber(&windows, i, &Desk) == 0) break; if (DeskOnly && Desk != DeskNumber) break; if (!GetItemGeometry(&windows, i, &pold_g)) break; if (PageOnly && !fvwmrect_do_rectangles_intersect(pold_g, &global_scr_g)) break; if (ScreenOnly && !fvwmrect_do_rectangles_intersect(pold_g, &screen_g)) break; if (UseSkipList && IsItemIndexSkipWindowList(&windows, i)) break; AddButton(&buttons, string, NULL, BUTTON_UP, i, IsItemIndexIconified(&windows, i)); redraw = 1; } else redraw = 0; break; case M_DEICONIFY: case M_ICONIFY: /* fwvm will wait for an Unlock message before continuing * be careful when changing this construct, make sure unlock happens * if AnimCommand && AnimCommand[0] != 0 */ iconified = IsItemIconified(&windows, body[0]); if (((i = FindItem(&windows, body[0])) == -1) || (type == M_DEICONIFY && !iconified) || (type == M_ICONIFY && iconified)) { if (AnimCommand && AnimCommand[0] != 0) SendUnlockNotification(Fvwm_fd); break; } iconified = !iconified; UpdateItemIconifiedFlag(&windows, body[0], iconified); { Button *temp = find_n(&buttons, i); if (temp) { Bool do_reshade = False; direction_t shade_dir = win_shade_direction; char buff[MAX_MODULE_INPUT_TEXT_LEN]; if (AnimCommand && (AnimCommand[0] != 0) && IsItemIndexIconSuppressed(&windows,i)) { Window child; int x, y; int abs_x, abs_y; if (win_is_shaded) { SendText(Fvwm_fd, "WindowShade Off", win); do_reshade = True; } ButtonCoordinates(&buttons, i, &x, &y); XTranslateCoordinates(dpy, win, Root, x, y, &abs_x, &abs_y, &child); if (type == M_DEICONIFY) { sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand, abs_x, abs_y, buttons.tw-2, RowHeight, (int)body[7], (int)body[8], (int)body[9], (int)body[10]); } else { sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand, (int)body[7], (int)body[8], (int)body[9], (int)body[10], abs_x, abs_y, buttons.tw-2, RowHeight); } SendText(Fvwm_fd, buff, 0); } temp->needsupdate = 1; temp->iconified = iconified; DrawButtonArray(&buttons, 0, NULL); if (do_reshade) { sprintf( buff,"WindowShade %s", gravity_dir_to_string(shade_dir,"")); SendText(Fvwm_fd, buff, win); } } if (AnimCommand && AnimCommand[0] != 0) SendUnlockNotification(Fvwm_fd); } if (type == M_ICONIFY && i == ButReleased) { RadioButton(&buttons, -1, BUTTON_UP); ButReleased = ButPressed = -1; redraw = 0; } break; case M_END_WINDOWLIST: AdjustWindow(win_width, win_height); XMapRaised(dpy, win); if (AutoHide) WindowState = -1; else WindowState = 1; break; case M_NEW_DESK: DeskNumber = body[0]; if (!First && DeskOnly) redraw_buttons(); else First = 0; break; case M_NEW_PAGE: break; case MX_PROPERTY_CHANGE: if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND && body[2] == 0 && CSET_IS_TRANSPARENT_PR(colorset)) { SetWindowBackground( dpy, win, win_width, win_height, &Colorset[colorset], Pdepth, graph, True); redraw = 1; } break; case M_CONFIG_INFO: { char *tline; int cset; tline = (char*)&(body[3]); if (strncasecmp(tline, "Colorset", 8) == 0) { cset = LoadColorset(tline + 8); if (change_colorset(cset, False)) { redraw = 1; } } else if (strncasecmp(tline, XINERAMA_CONFIG_STRING, sizeof(XINERAMA_CONFIG_STRING) - 1) == 0) { FScreenConfigureModule( tline + sizeof(XINERAMA_CONFIG_STRING) - 1); } } break; } /* switch */ if (redraw >= 0) RedrawWindow(redraw, NULL); } void redraw_buttons(void) { Item *item; FreeAllButtons(&buttons); for (item=windows.head; item; item=item->next) { if ((DeskNumber != item->Desk && !IS_STICKY_ACROSS_DESKS(item) && (!IS_ICONIFIED(item) || !IS_ICON_STICKY_ACROSS_DESKS(item)))) { continue; } if (DO_SKIP_WINDOW_LIST(item) && UseSkipList) { continue; } if (PageOnly && !fvwmrect_do_rectangles_intersect(&item->win_g, &global_scr_g)) { continue; } AddButton( &buttons, item->name, &(item->p), BUTTON_UP, item->count, IS_ICONIFIED(item)); } RedrawWindow(1, NULL); } /* Detected a broken pipe - time to exit Based on DeadPipe() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ RETSIGTYPE DeadPipe(int nonsense) { is_dead_pipe = True; exit(1); SIGNAL_RETURN; } /* Reentrant signal handler that will tell the application to quit. It is not safe to just call "exit()" here; instead we will just set a flag that will break the event-loop when the handler returns. */ static RETSIGTYPE TerminateHandler(int sig) { fvwmSetTerminate(sig); SIGNAL_RETURN; } #if 0 /* WaitForExpose - Used to wait for expose event so we don't draw too early */ void WaitForExpose(void) { XEvent Event; while(1) { FNextEvent(dpy, &Event); if (Event.type == Expose) { if (Event.xexpose.count == 0) break; } } } #endif /* RedrawWindow - Update the needed lines and erase any old ones */ void RedrawWindow(int force, XEvent *evp) { if (Tip.open) { RedrawTipWindow(); /* 98-11-21 13:45, Mohsin_Ahmed, mailto:mosh@sasi.com. */ if( Tip.type >= 0 && AutoFocus ) { SendFvwmPipe( Fvwm_fd, "Iconify off, Raise, Focus", ItemID( &windows, Tip.type ) ); } } if (force) { if (evp) { XClearArea( dpy, win, evp->xexpose.x, evp->xexpose.y, evp->xexpose.width, evp->xexpose.height, False); } else { XClearArea( dpy, win, 0, 0, win_width, win_height, False); } DrawGoodies(evp); } DrawButtonArray(&buttons, force, evp); StartButtonDraw(force, evp); if (FQLength(dpy) && !force) LoopOnEvents(); } static char *configopts[] = { "imagepath", "colorset", XINERAMA_CONFIG_STRING, NULL }; static char *moduleopts[] = { "Font", "SelFont", "Geometry", "Fore", "Back", "Colorset", "IconFore", "IconBack", "IconColorset", "Action", "UseSkipList", "AutoFocus", "AutoStick", "AutoHide", "UseIconNames", "ShowTransients", "DeskOnly", "UpdateInterval", "HighlightFocus", "ButtonWidth", "NoIconAction", "NoBrightFocus", "FocusFore", "FocusBack", "FocusColorset", "3DFvwm", "Rows", "PageOnly", "ScreenOnly", "Pad", NULL }; void ParseConfig(void) { char *buf; InitGetConfigLine(Fvwm_fd,CatString3("*",module->name,0)); while (GetConfigLine(Fvwm_fd,&buf), buf != NULL) { ParseConfigLine(buf); } /* end config lines */ } /* end function */ static void ParseConfigLine(char *tline) { char *rest; int index; while (isspace((unsigned char)*tline)) tline++; if (strncasecmp(tline, CatString3("*",module->name,0), module->namelen) != 0) { /* Non module specific options */ index = GetTokenIndex(tline, configopts, -1, &rest); while (*rest && *rest != '\n' && isspace(*rest)) rest++; switch(index) { case 0: /* imagepath */ if (ImagePath) { free(ImagePath); } CopyString(&ImagePath, rest); break; case 1: /* colorset */ LoadColorset(rest); break; case 2: /* XINERAMA_CONFIG_STRING */ if (XineramaConfig) { free(XineramaConfig); } CopyString(&XineramaConfig, rest); break; default: /* unknown option */ break; } } /* if options */ else { /* options beginning with '*ModuleName' */ rest = tline + module->namelen+1; index = GetTokenIndex(rest, moduleopts, -1, &rest); while (*rest && *rest != '\n' && isspace(*rest)) rest++; switch(index) { case 0: /* Font */ CopyStringWithQuotes(&font_string, rest); break; case 1: /* SelFont */ CopyStringWithQuotes(&selfont_string, rest); break; case 2: /* Geometry */ while (isspace((unsigned char)*rest) && *rest != '\n' && *rest != 0) rest++; UpdateString(&geometry, PeekToken(rest, NULL)); break; case 3: /* Fore */ CopyString(&ForeColor, rest); colorset = -1; break; case 4: /* Back */ CopyString(&BackColor, rest); colorset = -1; break; case 5: /* Colorset */ colorset = atoi(rest); if (colorset < 0) { colorset = -1; } AllocColorset(colorset); break; case 6: /* IconFore */ CopyString(&IconForeColor, rest); iconcolorset = -1; break; case 7: /* IconBack */ CopyString(&IconBackColor, rest); iconcolorset = -1; break; case 8: /* IconColorset */ iconcolorset = atoi(rest); if (iconcolorset < 0) { iconcolorset = -1; } AllocColorset(iconcolorset); break; case 9: /* Action */ LinkAction(rest); break; case 10: /* UseSkipList */ UseSkipList=True; break; case 11: /* AutoFocus */ AutoFocus=True; break; case 12: /* AutoStick */ AutoStick=True; break; case 13: /* AutoHide */ AutoHide=True; AutoStick=True; VisiblePixels=atoi(rest); if (VisiblePixels < 1) { VisiblePixels = DEFAULT_VISIBLE_PIXELS; } break; case 14: /* UseIconNames */ UseIconNames=True; break; case 15: /* ShowTransients */ ShowTransients=True; break; case 16: /* DeskOnly */ DeskOnly=True; break; case 17: /* UpdateInterval */ UpdateInterval = atoi(rest); if (UpdateInterval < 0) { UpdateInterval = 30; } break; case 18: /* HighlightFocus */ HighlightFocus=True; break; case 19: /* ButtonWidth */ button_width = atoi(rest); if (button_width < 0) { button_width = DEFAULT_BTN_WIDTH; } break; case 20: /* NoIconAction */ CopyString(&AnimCommand, rest); if (strlen(AnimCommand) > MAX_NO_ICON_ACTION_LENGTH) AnimCommand[MAX_NO_ICON_ACTION_LENGTH] = 0; break; case 21: /* NoBrightFocus */ NoBrightFocus = True; break; case 22: /* FocusFore */ CopyString(&FocusForeColor, rest); focuscolorset = -1; break; case 23: /* FocusBack */ CopyString(&FocusBackColor, rest); focuscolorset = -1; break; case 24: /* FocusColorset */ focuscolorset = atoi(rest); if (focuscolorset < 0) { focuscolorset = -1; } AllocColorset(focuscolorset); break; case 25: /* 3DFvwm */ ThreeDfvwm = True; break; case 26: /* Rows */ RowsNumber = atoi(rest); if (!(1 <= RowsNumber && RowsNumber <= 8)) { RowsNumber = 1; } break; case 27: /* PageOnly */ PageOnly=True; break; case 28: /* ScreenOnly */ ScreenOnly=True; break; case 29: /* Pad */ pad = atoi(rest); if (pad < 0) { pad = 3; } break; default: if (!GoodiesParseConfig(tline) && !StartButtonParseConfig(tline)) { fprintf(stderr,"%s: unknown configuration option %s", module->name, tline); } break; } /* switch */ } /* else options */ } /* Alarm - Handle a SIGALRM - used to implement timeout events */ static RETSIGTYPE Alarm(int nonsense) { if (AlarmSet & SHOW_TIP) { tip_window_alarm = True; } if (AlarmSet & HIDE_TASK_BAR) { hide_taskbar_alarm = True; } if (AlarmSet & STICK_TASK_BAR) { stick_taskbar_alarm = True; } AlarmSet = NOT_SET; #if !defined(HAVE_SIGACTION) && !defined(USE_BSD_SIGNALS) signal (SIGALRM, Alarm); #endif SIGNAL_RETURN; } /* DoAlarmAction - */ void DoAlarmAction(void) { if (hide_taskbar_alarm) { hide_taskbar_alarm = False; HideTaskBar(); } if (stick_taskbar_alarm) { stick_taskbar_alarm = False; WarpTaskBar(auto_stick_y); } if (tip_window_alarm) { tip_window_alarm = False; if (AutoHide && WindowState == 0) { Window dummy_rt, dummy_c; int abs_x, abs_y, pos_x, pos_y; unsigned int dummy; XEvent sevent; /* We are now "sure" that the TaskBar is not hidden for the Event loop. We send a motion notify for activating tips */ WindowState = 1; if (FQueryPointer(dpy, win, &dummy_rt,&dummy_c, &abs_x, &abs_y, &pos_x, &pos_y, &dummy) == False) { /* pointer is on a different screen */ abs_x = 0; abs_y = 0; } sevent.xmotion.x = pos_x; sevent.xmotion.y = pos_y; sevent.xany.type = MotionNotify; sevent.xmotion.state = 0; FSendEvent(dpy, win, False, EnterWindowMask, &sevent); Tip.type = NO_TIP; } else ShowTipWindow(1); } } /* CheckForTip - determine when to popup the tip window */ void CheckForTip(int x, int y) { int num, bx, by, trunc; char *name; if (MouseInStartButton(x, y, &whichButton, &startButtonPressed, NULL)) { if((!whichButton) && (First_Start_Button->isStartButton)) { if (Tip.type != START_TIP) PopupTipWindow(3, 0, _("Click here to start")); Tip.type = START_TIP; } else Tip.type = NO_TIP; } else if (MouseInMail(x, y)) { if (Tip.type != MAIL_TIP) CreateMailTipWindow(); Tip.type = MAIL_TIP; } else if (MouseInClock(x, y)) { if (Tip.type != DATE_TIP) CreateDateWindow(); Tip.type = DATE_TIP; } else { num = LocateButton(&buttons, x, y, &bx, &by, &name, &trunc); if (num != -1) { if ((Tip.type != num) || (Tip.text == NULL) || (!trunc && (strcmp(name, Tip.text) != 0))) PopupTipWindow(bx+3, by, name); Tip.type = num; } else { Tip.type = NO_TIP; } } if (Tip.type != NO_TIP) { if (AlarmSet != SHOW_TIP && !Tip.open) SetAlarm(SHOW_TIP); } else { ClearAlarm(SHOW_TIP); if (Tip.open) { ShowTipWindow(0); } } } /* HandleButtonRelease - Process a ButtonRelease X event */ void HandleButtonRelease( XEvent *evp, Time *NewTimestamp, int *redraw) { int num = 0; int tmp_x; char *tmp; *NewTimestamp = evp->xbutton.time; num = WhichButton( &buttons, evp->xbutton.x, evp->xbutton.y); StartButtonUpdate(NULL, -1, BUTTON_UP); if (num == -1) { if (MouseInStartButton( evp->xbutton.x, evp->xbutton.y, &whichButton, &startButtonPressed, &tmp_x)) { if (whichButton == ButtonPressed) { rectangle r; Window tmpw; r.x = tmp_x; r.y = 0; r.width = StartAndLaunchButtonsWidth; r.height = StartAndLaunchButtonsHeight; XTranslateCoordinates( dpy, win, Root, r.x, r.y, &r.x, &r.y, &tmpw); if ((First_Start_Button->buttonStartCommand != NULL) && (startButtonPressed)) { tmp = module_expand_action( dpy, screen, First_Start_Button-> buttonStartCommand, &r, NULL, NULL); if (tmp) { SendText(Fvwm_fd, tmp, 0); free(tmp); } else { SendText( Fvwm_fd, First_Start_Button-> buttonStartCommand, 0); } } else { char *tmp2; tmp = (char *)safemalloc( 100 * sizeof(char)); *tmp = 0; getButtonCommand( whichButton, tmp, evp->xbutton.button); tmp2 = module_expand_action( dpy, screen, tmp, &r, NULL, NULL); if (tmp2) { SendText(Fvwm_fd, tmp2, 0); free(tmp2); } else if (*tmp != 0) { SendText(Fvwm_fd, tmp, 0); } free(tmp); } } } } else { ButReleased = ButPressed; /* Avoid race fvwm pipe */ if (evp->xbutton.button >= 1 && evp->xbutton.button <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS) { rectangle r; Window tmpw; ButtonCoordinates(&buttons, num, &r.x, &r.y); ButtonDimensions(&buttons, &r.width, &r.height); XTranslateCoordinates( dpy, win, Root, r.x, r.y, &r.x, &r.y, &tmpw); tmp = module_expand_action( dpy, screen, ClickAction[evp->xbutton.button-1], &r, NULL, NULL); if (tmp) { SendFvwmPipe( Fvwm_fd, tmp, ItemID(&windows, num)); free(tmp); } else { SendFvwmPipe( Fvwm_fd, ClickAction[evp->xbutton.button-1], ItemID(&windows, num)); } } } if (MouseInStartButton( evp->xbutton.x, evp->xbutton.y, &whichButton, &startButtonPressed, NULL)) { *redraw = 0; usleep(50000); } if (HighlightFocus) { if (num == ButPressed) RadioButton(&buttons, num, BUTTON_DOWN); if (num != -1) SendText( Fvwm_fd, "Focus 0", ItemID(&windows, num)); } ButPressed = -1; *redraw = 0; } /* HandleEvents - Process an X event */ void HandleEvents( XEvent *evp, Time *NewTimestamp, int *redraw, int *expose_redraw) { int num = 0; XEvent *evp_save; int x, y; int ex=10000, ey=10000, ex2=0, ey2=0; *redraw = -1; *expose_redraw = False; switch(evp->type) { case ButtonRelease: HandleButtonRelease(evp, NewTimestamp, redraw); break; case ButtonPress: *NewTimestamp = evp->xbutton.time; RadioButton(&buttons, -1, BUTTON_UP); /* no windows focused * anymore */ if (MouseInStartButton( evp->xbutton.x, evp->xbutton.y, &whichButton, &startButtonPressed, NULL)) { StartButtonUpdate(NULL, whichButton, BUTTON_DOWN); ButtonPressed = whichButton; x = win_x; if (win_y < Midline) { /* bar in top half of the screen */ y = win_y + RowHeight; } else { /* bar in bottom of the screen */ y = win_y - screen_g.height; } } else { StartButtonUpdate(NULL, whichButton, BUTTON_UP); if (MouseInMail(evp->xbutton.x, evp->xbutton.y)) { HandleMailClick(*evp); } else { num = WhichButton( &buttons, evp->xbutton.x, evp->xbutton.y); UpdateButton(&buttons, num, NULL, (ButPressed == num) ? BUTTON_BRIGHT : BUTTON_DOWN); ButPressed = num; } } *redraw = 0; break; case Expose: if (evp->xexpose.window == Tip.win) { while (FCheckTypedWindowEvent( dpy, evp->xexpose.window, Expose, evp)); if (Tip.open) { RedrawTipWindow(); } break; } /* eat up excess Expose events. */ ex = evp->xexpose.x; ey = evp->xexpose.y; ex2 = evp->xexpose.x + evp->xexpose.width; ey2 = evp->xexpose.y + evp->xexpose.height; while (FCheckTypedWindowEvent(dpy, win, Expose, evp)) { ex = min(ex, evp->xexpose.x); ey = min(ey, evp->xexpose.y); ex2 = max(ex2, evp->xexpose.x + evp->xexpose.width); ey2= max(ey2 , evp->xexpose.y + evp->xexpose.height); } evp->xexpose.x = ex; evp->xexpose.y = ey; evp->xexpose.width = ex2 - ex; evp->xexpose.height = ey2 - ey; *redraw = 1; *expose_redraw = True; break; case ClientMessage: if ((evp->xclient.format==32) && (evp->xclient.data.l[0]==wm_del_win)) exit(0); break; case EnterNotify: *NewTimestamp = evp->xcrossing.time; if (AutoHide) { RevealTaskBar(); } if (evp->xcrossing.mode != NotifyNormal) break; num = WhichButton( &buttons, evp->xcrossing.x, evp->xcrossing.y); if (!HighlightFocus) { if (SomeButtonDown(evp->xcrossing.state)) { if (num != -1) { RadioButton(&buttons, num, BUTTON_DOWN); ButPressed = num; *redraw = 0; } else { ButPressed = -1; } } } else { if (num != -1 && num != ButPressed) SendText( Fvwm_fd, "Focus 0", ItemID(&windows, num)); } CheckForTip(evp->xcrossing.x, evp->xcrossing.y); break; case LeaveNotify: *NewTimestamp = evp->xcrossing.time; ClearAlarm(SHOW_TIP); if (Tip.open) { ShowTipWindow(0); } if (AutoHide) SetAlarm(HIDE_TASK_BAR); if (evp->xcrossing.mode != NotifyNormal) break; if (!HighlightFocus) { if (SomeButtonDown(evp->xcrossing.state)) { if (ButPressed != -1) { RadioButton(&buttons, -1, BUTTON_UP); ButPressed = -1; *redraw = 0; } } else { if (ButReleased != -1) { RadioButton(&buttons, -1, BUTTON_UP); ButReleased = -1; *redraw = 0; } } } break; case MotionNotify: *NewTimestamp = evp->xmotion.time; if (MouseInStartButton( evp->xmotion.x, evp->xbutton.y, &whichButton, &startButtonPressed, NULL)) { CheckForTip(evp->xmotion.x, evp->xmotion.y); break; } num = WhichButton(&buttons, evp->xmotion.x, evp->xmotion.y); if (!HighlightFocus) { if (SomeButtonDown(evp->xmotion.state) && num != ButPressed) { if (num != -1) { RadioButton(&buttons, num, BUTTON_DOWN); ButPressed = num; } else { RadioButton(&buttons, num, BUTTON_UP); ButPressed = -1; } *redraw = 0; } } else if (num != -1 && num != ButPressed) SendText(Fvwm_fd, "Focus 0", ItemID(&windows, num)); CheckForTip(evp->xmotion.x, evp->xmotion.y); break; case ConfigureNotify: { Bool moved = False; int cx = win_x, cy = win_y; /* eat up excess ConfigureNotify events. */ if (evp->xconfigure.send_event) { moved = True; cx = evp->xconfigure.x; cy = evp->xconfigure.y; } evp_save = evp; while (FCheckTypedWindowEvent(dpy, win, ConfigureNotify, evp)) { evp_save = evp; if (evp->xconfigure.send_event) { moved = True; cx = evp->xconfigure.x; cy = evp->xconfigure.y; } } evp = evp_save; if (evp->xconfigure.height != win_height) { AdjustWindow( evp->xconfigure.width, evp->xconfigure.height); if (colorset >= 0) { SetWindowBackground( dpy, win, win_width, win_height, &Colorset[colorset], Pdepth, graph, True); } *redraw = 1; } /* useful because of dynamic style change */ if (!moved) { break; } else if (cx != win_x || cy != win_y) { if (CSET_IS_TRANSPARENT(colorset)) { SetWindowBackground( dpy, win, win_width, win_height, &Colorset[colorset], Pdepth, graph, True); *redraw = 1; } else if (CheckRootTransparentButtons(&buttons)) { *redraw = 0; } if (AutoStick) { SetAlarm(STICK_TASK_BAR); auto_stick_y = evp->xconfigure.y; } else { win_x = cx; win_y = cy; } } } break; } /* switch evp->type */ XSync(dpy,0); /* needed (tips) */ } /* LoopOnEvents - Process all the X events we get */ void LoopOnEvents(void) { XEvent Event; int redraw, expose_redraw; static unsigned long lasttime = 0L; Time NewTimestamp = lasttime; while(FPending(dpy)) { redraw = -1; expose_redraw = False, FNextEvent(dpy, &Event); NewTimestamp = lasttime; HandleEvents(&Event, &NewTimestamp, &redraw, &expose_redraw); if (redraw >= 0) { RedrawWindow(redraw, (expose_redraw)? &Event:NULL); } DoAlarmAction(); if (NewTimestamp - lasttime > UpdateInterval*1000L) { DrawGoodies(NULL); lasttime = NewTimestamp; } } return; } /* AdjustWindow - Resize the window */ void AdjustWindow(int width, int height) { NRows = (height+2)/RowHeight; if (NRows <= 0) { NRows = 1; } win_height = height; win_width = width; ArrangeButtonArray(&buttons); change_colorset(0, False); } /* LinkAction - Link an response to a users action */ void LinkAction(const char *string) { const char *temp=string; while(isspace((unsigned char)*temp)) temp++; if(strncasecmp(temp, "Click", 5)==0) { int n; int b; int i; i = sscanf(temp + 5, "%d%n", &b, &n); if (i > 0 && b >=1 && b <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS) { CopyString(&ClickAction[b - 1], temp + 5 + n); } } else if(strncasecmp(temp, "Enter", 5)==0) CopyString(&EnterAction,&temp[5]); } static void CreateOrUpdateGCs(void) { XGCValues gcval; unsigned long gcmask; Pixel pfore; Pixel pback; Pixel piconfore; Pixel piconback; Pixel piconhilite; Pixel piconshadow; Pixel pfocusfore; Pixel pfocusback; Pixel pfocushilite; Pixel pfocusshadow; Pixel philite; Pixel pshadow; if (colorset >= 0) { pfore = Colorset[colorset].fg; pback = Colorset[colorset].bg; philite = Colorset[colorset].hilite; pshadow = Colorset[colorset].shadow; } else { pfore = fore; pback = back; philite = GetHilite(back); if(Pdepth < 2) pshadow = GetShadow(fore); else pshadow = GetShadow(back); } if (iconcolorset >= 0) { piconfore = Colorset[iconcolorset].fg; piconback = Colorset[iconcolorset].bg; piconhilite = Colorset[iconcolorset].hilite; piconshadow = Colorset[iconcolorset].shadow; } else { piconfore = iconfore; piconback = iconback; piconhilite = GetHilite(iconback); if(Pdepth < 2) piconshadow = GetShadow(iconfore); else piconshadow = GetShadow(iconback); } if (focuscolorset >= 0) { pfocusfore = Colorset[focuscolorset].fg; pfocusback = Colorset[focuscolorset].bg; pfocushilite = Colorset[focuscolorset].hilite; pfocusshadow = Colorset[focuscolorset].shadow; } else { pfocusshadow = pshadow; if (FocusForeColor != NULL) { pfocusfore = focusfore; if(Pdepth < 2) pfocusshadow = GetShadow(focusfore); } else { pfocusfore = fore; } if (FocusBackColor != NULL) { pfocusback = focusback; pfocushilite = GetHilite(focusback); if(!(Pdepth < 2)) pfocusshadow = GetShadow(focusback); } else { pfocusback = back; pfocushilite = philite; } } /* only the foreground changes for all GCs */ gcval.background = pback; gcval.graphics_exposures = False; gcmask = GCForeground | GCBackground | GCGraphicsExposures; if (FSelButtonFont->font != NULL) { gcmask |= GCFont; gcval.font = FSelButtonFont->font->fid; } /* Normal */ gcval.foreground = pfore; if (graph) XChangeGC(dpy,graph,gcmask,&gcval); else graph = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); /* iconified */ gcval.foreground = piconfore; if (iconbackgraph) XChangeGC(dpy,icongraph,gcmask,&gcval); else icongraph = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = piconback; if (iconbackgraph) XChangeGC(dpy,iconbackgraph,gcmask,&gcval); else iconbackgraph = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = piconshadow; if (iconshadow) XChangeGC(dpy,iconshadow,gcmask,&gcval); else iconshadow = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = piconhilite; if (iconhilite) XChangeGC(dpy,iconhilite,gcmask,&gcval); else iconhilite = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); /* focused */ gcval.foreground = pfocusfore; if (focusbackgraph) XChangeGC(dpy,focusgraph,gcmask,&gcval); else focusgraph = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = pfocusback; if (focusbackgraph) XChangeGC(dpy,focusbackgraph,gcmask,&gcval); else focusbackgraph = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = pfocusshadow; if (focusshadow) XChangeGC(dpy,focusshadow,gcmask,&gcval); else focusshadow = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = pfocushilite; if (focushilite) XChangeGC(dpy,focushilite,gcmask,&gcval); else focushilite = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); /* "normal" continued */ gcmask = GCForeground | GCBackground | GCGraphicsExposures; gcval.foreground = pshadow; if (shadow) XChangeGC(dpy,shadow,gcmask,&gcval); else shadow = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = philite; if (hilite) XChangeGC(dpy,hilite,gcmask,&gcval); else hilite = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = PictureWhitePixel(); if (whitegc) XChangeGC(dpy,whitegc,gcmask,&gcval); else whitegc = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground = PictureBlackPixel(); if (blackgc) XChangeGC(dpy,blackgc,gcmask,&gcval); else blackgc = fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); /* brighting */ gcmask = GCForeground | GCBackground | GCTile | GCFillStyle | GCGraphicsExposures; if (focuscolorset >= 0 || FocusBackColor != NULL) gcval.foreground = pfocusback; else gcval.foreground = philite; gcval.fill_style = FillTiled; gcval.tile = XCreatePixmapFromBitmapData(dpy, win, (char *)gray_bits, gray_width, gray_height, gcval.foreground, gcval.background,Pdepth); if (checkered) XChangeGC(dpy, checkered, gcmask, &gcval); else checkered = fvwmlib_XCreateGC(dpy, win, gcmask, &gcval); } static Bool change_colorset(int cset, Bool force) { Bool do_redraw = False; if (cset < 0) return False; if (force || cset == colorset || cset == iconcolorset || cset == focuscolorset) { CreateOrUpdateGCs(); if (force || cset == colorset) { SetWindowBackground( dpy, win, win_width, win_height, &Colorset[colorset], Pdepth, graph, True); } do_redraw = True; } do_redraw |= change_goody_colorset(cset, force); return do_redraw; } /* StartMeUp - Do X initialization things */ void StartMeUp(void) { XSizeHints hints; XClassHint classhints; int ret; int i; XSetWindowAttributes attr; int wx; int wy; if (!(dpy = XOpenDisplay(""))) { fprintf(stderr,"%s: can't open display %s", module->name, XDisplayName("")); exit (1); } flib_init_graphics(dpy); if (XineramaConfig) { FScreenConfigureModule(XineramaConfig); free(XineramaConfig); } FlocaleAllocateWinString(&FwinString); x_fd = XConnectionNumber(dpy); screen= DefaultScreen(dpy); Root = RootWindow(dpy, screen); if (geometry == NULL) UpdateString(&geometry, "+0-0"); /* evaluate further down */ ret = FScreenParseGeometryWithScreen( geometry, &wx, &wy, (unsigned int *)&hints.width, (unsigned int *)&hints.height, &fscreen); FScreenGetScrRect( NULL, fscreen, &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height); FScreenGetScrRect( NULL, FSCREEN_GLOBAL, &global_scr_g.x, &global_scr_g.y, &global_scr_g.width, &global_scr_g.height); Midline = (screen_g.height >> 1) + screen_g.y; if (selfont_string == NULL) selfont_string = font_string; if ((FButtonFont = FlocaleLoadFont(dpy, font_string,module->name)) == NULL) { fprintf(stderr, "%s: Couldn't load font. Exiting!\n",module->name); exit(1); } if ((FSelButtonFont = FlocaleLoadFont(dpy, selfont_string,module->name)) == NULL) { fprintf(stderr, "%s: Couldn't load font. Exiting!\n",module->name); exit(1); } LoadGoodiesFont(); fontheight = (FButtonFont->height > FSelButtonFont->height)? FButtonFont->height : FSelButtonFont->height; if (goodies_fontheight > fontheight) fontheight = goodies_fontheight; NRows = 1; RowHeight = fontheight + 8; win_border = 4; /* default border width */ win_height = RowHeight+(RowsNumber-1)*(RowHeight+2); win_width = screen_g.width - (win_border * 2); /* now evaluate the geometry parsed above */ if (ret & YNegative) { if (AutoStick) { if (-wy < Midline) wy = screen_g.height - (AutoHide ? VISIBLE_PIXELS() : win_height); else wy = AutoHide ? VISIBLE_PIXELS() - win_height : 0; wy += screen_g.y; } else { wy += screen_g.height - win_height; } } else if (AutoStick) { if (wy < Midline) wy = AutoHide ? VISIBLE_PIXELS() - win_height : 0; else wy = screen_g.height - (AutoHide ? VISIBLE_PIXELS() : win_height); wy += screen_g.y; } if (ret & XNegative) { if (ret & YNegative) hints.win_gravity=SouthEastGravity; else hints.win_gravity=NorthEastGravity; } else { if (ret & YNegative) hints.win_gravity=SouthWestGravity; else hints.win_gravity=NorthWestGravity; } hints.flags=USPosition|PPosition|USSize|PSize|PResizeInc| PWinGravity|PMinSize|PMaxSize|PBaseSize; wx = screen_g.x; hints.width = win_width; hints.height = win_height; hints.width_inc = 1; hints.height_inc = RowHeight+2; hints.min_width = win_width; hints.min_height = RowHeight; hints.max_width = win_width; hints.max_height = RowHeight+7*(RowHeight+2); hints.base_width = win_width; hints.base_height = RowHeight; win_x = wx + win_border; win_y = wy; if(Pdepth < 2) { back = PictureWhitePixel(); fore = PictureBlackPixel(); iconback = PictureWhitePixel(); iconfore = PictureBlackPixel(); focusback = PictureWhitePixel(); focusfore = PictureBlackPixel(); } else { back = GetColor(BackColor); fore = GetColor(ForeColor); iconback = GetColor(IconBackColor); iconfore = GetColor(IconForeColor); if (FocusBackColor != NULL) focusback = GetColor(FocusBackColor); else focusback = back; if (FocusForeColor != NULL) focusfore = GetColor(FocusForeColor); else focusfore = fore; } attr.background_pixel = (colorset >= 0) ? Colorset[colorset].bg : back; attr.border_pixel = 0; attr.colormap = Pcmap; win=XCreateWindow(dpy,Root,wx,wy,hints.width,hints.height,0,Pdepth, InputOutput,Pvisual,CWBackPixel|CWBorderPixel|CWColormap, &attr); wm_del_win=XInternAtom(dpy,"WM_DELETE_WINDOW",False); XSetWMProtocols(dpy,win,&wm_del_win,1); { XTextProperty nametext; char *list[]={NULL,NULL}; list[0] = module->name; classhints.res_name= module->name; classhints.res_class= "FvwmTaskBar"; if(!XStringListToTextProperty(list,1,&nametext)) { fprintf(stderr,"%s: Failed to convert name to XText\n",module->name); exit(1); } /* hack to prevent mapping on wrong screen with StartsOnScreen */ FScreenMangleScreenIntoUSPosHints(fscreen, &hints); XSetWMProperties(dpy,win,&nametext,&nametext, NULL,0,&hints,NULL,&classhints); XFree(nametext.value); } for (i = 1; i <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS; i++) { XGrabButton(dpy,i,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync, GrabModeAsync,None,None); } /* SetMwmHints(MWM_DECOR_ALL|MWM_DECOR_MAXIMIZE|MWM_DECOR_MINIMIZE, MWM_FUNC_ALL|MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE, MWM_INPUT_MODELESS); */ CreateOrUpdateGCs(); if (colorset >= 0) { SetWindowBackground( dpy, win, win_width, win_height, &Colorset[colorset], Pdepth, graph, False); } XSelectInput(dpy,win,(ExposureMask | KeyPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask)); InitGoodies(); atexit(ShutMeDown); } /* ShutMeDown - Do X client cleanup */ static void ShutMeDown(void) { if (!is_dead_pipe) { FreeList(&windows); FreeAllButtons(&buttons); XFreeGC(dpy,graph); XFreeGC(dpy,icongraph); XFreeGC(dpy,focusgraph); XDestroyWindow(dpy, win); XCloseDisplay(dpy); } } /* ChangeWindowName - Self explanitory Original work from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ChangeWindowName(char *str) { XTextProperty name; if (XStringListToTextProperty(&str,1,&name) == 0) { fprintf(stderr,"%s: cannot allocate window name.\n",module->name); return; } XSetWMName(dpy,win,&name); XSetWMIconName(dpy,win,&name); XFree(name.value); } /* * * Sets mwm hints * */ /* * Now, if we (hopefully) have MWW - compatible window manager , * say, mwm, ncdwm, or else, we will set useful decoration style. * Never check for MWM_RUNNING property.May be considered bad. */ void SetMwmHints(unsigned int value, unsigned int funcs, unsigned int input) { PropMwmHints prop; if (MwmAtom==None) { MwmAtom=XInternAtom(dpy,"_MOTIF_WM_HINTS",False); } if (MwmAtom!=None) { /* sh->mwm.decorations contains OR of the MWM_DECOR_XXXXX */ prop.props[0] = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS | MWM_HINTS_INPUT_MODE; prop.props[1] = funcs; prop.props[2]= value; prop.props[3] = input; /* HOP - LA! */ XChangeProperty( dpy, win, MwmAtom, MwmAtom, 32, PropModeReplace, (unsigned char *)&(prop.props[0]), PROP_MWM_HINTS_ELEMENTS); } } /* WarpTaskBar -- Enforce AutoStick feature */ static void WarpTaskBar(int y) { /* The tests on y are really useful ! */ if (!AutoHide && ((y != screen_g.y + screen_g.height - win_height - win_border && y != screen_g.y + win_border))) { if (y > Midline) { win_y = screen_g.height - win_height - win_border; } else { win_y = win_border + win_title_height; } win_y += screen_g.y; XSync(dpy, 0); XMoveWindow(dpy, win, win_x, win_y); XSync(dpy, 0); } if (AutoHide) SetAlarm(HIDE_TASK_BAR); ClearAlarm(STICK_TASK_BAR); } /* SleepALittle -- do a small delay in a fairly portable way Replace "#if 1" with "#if 0" to turn delay off */ static void SleepALittle(void) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 10000; #if 1 XSync(dpy, 0); select(0, NULL, NULL, NULL, &tv); XSync(dpy, 0); #endif } /* RevealTaskBar -- Make taskbar fully visible */ void RevealTaskBar(void) { int new_win_y; int inc_y = 2; ClearAlarm(HIDE_TASK_BAR); /* do not reveal if the taskbar is already revealed */ if (WindowState >= 0) return; /* Go faster with the number of rows */ inc_y += (NRows >= 3 ? 3 : 0) + (NRows >= 5 ? 3 : 0); if (win_y < Midline) { new_win_y = screen_g.y + win_border + win_title_height; for (; win_y<=new_win_y; win_y +=inc_y) { XMoveWindow(dpy, win, win_x, win_y); SleepALittle(); } } else { new_win_y = screen_g.y + screen_g.height - win_height - win_border; for (; win_y>=new_win_y; win_y -=inc_y) { XMoveWindow(dpy, win, win_x, win_y); SleepALittle(); } } win_y = new_win_y; XMoveWindow(dpy, win, win_x, win_y); WindowState = 0; } /* HideTaskbar -- Make taskbar partially visible */ void HideTaskBar(void) { int new_win_y; int inc_y = 1; Window d_rt, d_ch; int d_x, d_y, wx, wy; unsigned int mask; ClearAlarm(HIDE_TASK_BAR); /* do not hide if the taskbar is already hiden */ if (WindowState == -1 || win_is_shaded) return; if (1||FocusInWin) { if (FQueryPointer( dpy, win, &d_rt,&d_ch, &d_x, &d_y, &wx, &wy, &mask) == False) { /* pointer is on a different screen - that's okay here */ } if (wy >= - (win_border + win_title_height * (win_title_dir != DIR_S)) && wy < win_height + win_border + win_title_height * (win_title_dir == DIR_S)) { if (wy < 0 || wy >= win_height || wx < 0 || wx >= win_width) SetAlarm(HIDE_TASK_BAR); return; } } /* Go faster with the number of rows */ inc_y += (NRows >= 3 ? 2 : 0) + (NRows >= 5 ? 2 : 0); if (win_y < Midline) { new_win_y = screen_g.y + VISIBLE_PIXELS() + win_title_height * (win_title_dir == DIR_S) - win_height; for (; win_y>=new_win_y; win_y -=inc_y) { XMoveWindow(dpy, win, win_x, win_y); SleepALittle(); } } else { new_win_y = screen_g.y + screen_g.height - VISIBLE_PIXELS() + win_title_height * (win_title_dir == DIR_S); for (; win_y<=new_win_y; win_y +=inc_y) { XMoveWindow(dpy, win, win_x, win_y); SleepALittle(); } } win_y = new_win_y; XMoveWindow(dpy, win, win_x, win_y); WindowState = -1; } /* SetAlarm -- Schedule a timeout event */ static void SetAlarm(tb_alarm_t event) { alarm(0); /* remove a race-condition */ AlarmSet |= event; alarm(1); } /* ClearAlarm -- Disable timeout events */ static void ClearAlarm(tb_alarm_t event) { AlarmSet &= ~event; if (AlarmSet == 0) { alarm(0); } } /* X Error Handler */ static int ErrorHandler(Display *d, XErrorEvent *event) { /* some errors are OK=ish */ if (event->error_code == BadPixmap) return 0; if (event->error_code == BadDrawable) return 0; if (FRenderGetErrorCodeBase() + FRenderBadPicture == event->error_code) return 0; PrintXErrorAndCoredump(d, event, module->name); return 0; }