/* -*-c-*- */ /* 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 "FvwmIconMan.h" #include "x.h" #include "xmanager.h" #include "libs/fvwmlib.h" #include "libs/FScreen.h" #include "libs/Module.h" #include "libs/Parse.h" #include "libs/Strings.h" static WinData *fvwm_focus_win = NULL; typedef struct { Ulong paging_enabled; } m_toggle_paging_data; typedef struct { Ulong desknum; } m_new_desk_data; typedef struct { Ulong x, y, desknum; } m_new_page_data; typedef struct { Ulong app_id, frame_id, dbase_entry; } m_minimal_data; typedef struct { Ulong app_id, frame_id, dbase_entry; Ulong xpos, ypos, icon_width, icon_height; } m_icon_data; typedef struct { Ulong app_id, frame_id, dbase_entry; union { Ulong name_long[1]; Uchar name[4]; } name; } m_name_data; typedef struct { Ulong arg, toggle, id; Uchar str[4]; } m_property_data; typedef struct { Ulong app_id, frame_id, dbase_entry; Ulong width, height, depth, picture, mask, alpha; union { Ulong name_long[1]; Uchar name[4]; } name; } m_mini_icon_data; typedef union { m_toggle_paging_data toggle_paging_data; m_new_desk_data new_desk_data; ConfigWinPacket add_config_data; m_new_page_data new_page_data; m_minimal_data minimal_data; m_icon_data icon_data; m_name_data name_data; m_mini_icon_data mini_icon_data; m_property_data property_data; } FvwmPacketBody; /* only used by count_nonsticky_in_hashtab */ static WinManager *the_manager; static int count_nonsticky_in_hashtab(void *arg) { WinData *win = (WinData *)arg; WinManager *man = the_manager; if (!(IS_STICKY_ACROSS_DESKS(win) || IS_STICKY_ACROSS_PAGES(win)) && !(WINDATA_ICONIFIED(win) && (IS_ICON_STICKY_ACROSS_PAGES(win) || IS_ICON_STICKY_ACROSS_DESKS(win))) && win->complete && win->manager == man) { return 1; } return 0; } static void set_draw_mode(WinManager *man, int flag) { int num; if (!man) { return; } if (man->we_are_drawing == 0 && flag) { draw_manager(man); } else if (man->we_are_drawing && !flag) { the_manager = man; num = accumulate_walk_hashtab(count_nonsticky_in_hashtab); ConsoleDebug( FVWM, "SetDrawMode on 0x%lx, num = %d\n", (unsigned long)man, num); if (num == 0) { return; } man->configures_expected = num; } man->we_are_drawing = flag; } static int drawing(WinManager *man) { if (!man) { return 1; } return man->we_are_drawing; } static void got_configure(WinManager *man) { if (man && !man->we_are_drawing) { man->configures_expected--; ConsoleDebug( FVWM, "got_configure on 0x%lx, num_expected now = %d\n", (unsigned long) man, man->configures_expected); if (man->configures_expected <= 0) { set_draw_mode(man, 1); } } } /* MMH <mikehan@best.com> 6/99 * Following a gruesome hack this function has been hijacked. * The function is no longer about whether or not the window is in the * viewport, but whether or not the manager wants to display the window, * based on its current location. */ int win_in_viewport(WinData *win) { return check_resolution(win->manager, win); } WinData *id_to_win(Ulong id) { WinData *win; win = find_win_hashtab(id); if (win == NULL) { win = new_windata(); win->app_id = id; win->app_id_set = 1; insert_win_hashtab(win); } return win; } static void set_win_configuration(WinData *win, FvwmPacketBody *body) { win->desknum = body->add_config_data.desk; win->x = body->add_config_data.frame_x; win->y = body->add_config_data.frame_y; win->width = body->add_config_data.frame_width; win->height = body->add_config_data.frame_height; win->iconified = IS_ICONIFIED(&(body->add_config_data)); win->state = (win == fvwm_focus_win) ? FOCUS_CONTEXT : PLAIN_CONTEXT; win->geometry_set = 1; memcpy(&(win->flags), &(body->add_config_data.flags), sizeof(win->flags)); { int wb_x = body->add_config_data.border_width; int wb_y = body->add_config_data.border_width; int t_w = 2*wb_x; int t_h = 2*wb_y; if (HAS_TITLE_DIR(win, DIR_N)) { wb_y += body->add_config_data.title_height; t_h += body->add_config_data.title_height; } else if (HAS_TITLE_DIR(win, DIR_W)) { wb_x += body->add_config_data.title_height; t_w += body->add_config_data.title_height; } if (HAS_TITLE_DIR(win, DIR_S)) { t_h += body->add_config_data.title_height; } if (HAS_TITLE_DIR(win, DIR_E)) { t_w += body->add_config_data.title_height; } win->real_g.x = win->x + wb_x; win->real_g.y = win->y + wb_y; win->real_g.width = win->width - t_w; win->real_g.height = win->height - t_h; } } static void handle_config_info(unsigned long *body) { char *tline, *token, *rest; int color; extern void process_dynamic_config_line(char *line); tline = (char*)&(body[3]); token = PeekToken(tline, &rest); if (StrEquals(token, "Colorset")) { color = LoadColorset(rest); change_colorset(color); } else if (StrEquals(token, XINERAMA_CONFIG_STRING)) { FScreenConfigureModule(rest); } else if (StrEquals(token, "IgnoreModifiers")) { sscanf(rest, "%d", &mods_unused); } else if (strncasecmp(tline, Module, ModuleLen) == 0) { process_dynamic_config_line(tline); } } static void configure_window(FvwmPacketBody *body) { Ulong app_id = body->add_config_data.w; WinData *win; ConsoleDebug(FVWM, "configure_window: %ld\n", app_id); win = id_to_win(app_id); set_win_configuration(win, body); check_win_complete(win); check_in_window(win); got_configure(win->manager); } static void focus_change(FvwmPacketBody *body) { Ulong app_id = body->minimal_data.app_id; WinData *win = id_to_win(app_id); ConsoleDebug(FVWM, "Focus Change\n"); ConsoleDebug(FVWM, "\tID: %ld\n", app_id); if (fvwm_focus_win && fvwm_focus_win->button && fvwm_focus_win->manager->showonlyfocused) delete_windows_button(fvwm_focus_win); if (fvwm_focus_win && win != fvwm_focus_win) { del_win_state(fvwm_focus_win, FOCUS_CONTEXT); if (fvwm_focus_win->manager && fvwm_focus_win->manager->focus_button) { fvwm_focus_win->manager->focus_button = NULL; } fvwm_focus_win = NULL; } if (win->complete && win->button && win->manager && win->manager->window_up && win->manager->followFocus) { win->manager->focus_button = win->button; } add_win_state(win, FOCUS_CONTEXT); check_in_window(win); globals.focus_win = win; fvwm_focus_win = win; ConsoleDebug(FVWM, "leaving focus_change\n"); } static void res_name(FvwmPacketBody *body) { Ulong app_id = body->name_data.app_id; Uchar *name = body->name_data.name.name; WinData *win; ConsoleDebug(FVWM, "In res_name\n"); win = id_to_win(app_id); copy_string(&win->resname, (char *)name); change_windows_manager(win); ConsoleDebug(FVWM, "Exiting res_name\n"); } static void class_name(FvwmPacketBody *body) { Ulong app_id = body->name_data.app_id; Uchar *name = body->name_data.name.name; WinData *win; ConsoleDebug(FVWM, "In class_name\n"); win = id_to_win(app_id); copy_string(&win->classname, (char *)name); change_windows_manager(win); ConsoleDebug(FVWM, "Exiting class_name\n"); } static void icon_name(FvwmPacketBody *body) { WinData *win; Ulong app_id; Uchar *name = body->name_data.name.name; ConsoleDebug(FVWM, "In icon_name\n"); app_id = body->name_data.app_id; win = id_to_win(app_id); if (win->iconname && !strcmp(win->iconname, (char *)name)) { ConsoleDebug( FVWM, "No icon change: %s %s\n", win->iconname, name); return; } copy_string(&win->iconname, (char *)name); ConsoleDebug(FVWM, "new icon name: %s\n", win->iconname); ConsoleDebug(FVWM, "Exiting icon_name\n"); } static void visible_icon_name(FvwmPacketBody *body) { WinData *win; Ulong app_id; Uchar *name = body->name_data.name.name; ConsoleDebug(FVWM, "In visible_icon_name\n"); app_id = body->name_data.app_id; win = id_to_win(app_id); if (win->visible_icon_name && !strcmp(win->visible_icon_name, (char *)name)) { ConsoleDebug( FVWM, "No icon change: %s %s\n", win->iconname, name); return; } copy_string(&win->visible_icon_name, (char *)name); ConsoleDebug( FVWM, "new visible icon name: %s\n", win->visible_icon_name); if (change_windows_manager(win) == 0 && win->button && (win->manager->format_depend & ICON_NAME)) { if (win->manager->sort) { resort_windows_button(win); } } ConsoleDebug(FVWM, "Exiting icon_name\n"); } static void window_name(FvwmPacketBody *body) { WinData *win; Ulong app_id; Uchar *name = body->name_data.name.name; ConsoleDebug(FVWM, "In window_name\n"); app_id = body->name_data.app_id; win = id_to_win(app_id); /* This is necessary because bash seems to update the window title on every keystroke regardless of whether anything changes */ if (win->titlename && !strcmp(win->titlename, (char *)name)) { ConsoleDebug( FVWM, "No name change: %s %s\n", win->titlename, name); return; } copy_string(&win->titlename, (char *)name); ConsoleDebug(FVWM, "Exiting window_name\n"); } static void visible_name(FvwmPacketBody *body) { WinData *win; Ulong app_id; Uchar *name = body->name_data.name.name; ConsoleDebug(FVWM, "In visible_name\n"); app_id = body->name_data.app_id; win = id_to_win(app_id); /* This is necessary because bash seems to update the window title on every keystroke regardless of whether anything changes */ if (win->visible_name && !strcmp(win->visible_name, (char *)name)) { ConsoleDebug( FVWM, "No visible name change: %s %s\n", win->visible_name, name); return; } copy_string(&win->visible_name, (char *)name); if (change_windows_manager(win) == 0 && win->button && (win->manager->format_depend & TITLE_NAME)) { if (win->manager->sort) { resort_windows_button(win); } } ConsoleDebug(FVWM, "Exiting visible_name\n"); } static void new_window(FvwmPacketBody *body) { WinData *win; win = id_to_win(body->add_config_data.w); memcpy(&(win->flags), &(body->add_config_data.flags), sizeof(win->flags)); set_win_configuration(win, body); got_configure(win->manager); check_win_complete(win); check_in_window(win); /* FIXME: not perfect, the manager is not know yet */ tips_cancel(win->manager); } static void destroy_window(FvwmPacketBody *body) { WinData *win; Ulong app_id; app_id = body->minimal_data.app_id; win = id_to_win(app_id); if (win->manager) { tips_cancel(win->manager); } if (win == globals.focus_win) { globals.focus_win = NULL; } delete_win_hashtab(win); if (win->button) { ConsoleDebug(FVWM, "destroy_window: deleting windows_button\n"); delete_windows_button(win); } if (win == fvwm_focus_win) { fvwm_focus_win = NULL; } free_windata(win); } static void mini_icon(FvwmPacketBody *body) { Ulong app_id = body->mini_icon_data.app_id; WinData *win; if (!FMiniIconsSupported) { return; } win = id_to_win(app_id); set_win_picture( win, body->mini_icon_data.picture, body->mini_icon_data.mask, body->mini_icon_data.alpha, body->mini_icon_data.depth, body->mini_icon_data.width, body->mini_icon_data.height); ConsoleDebug( FVWM, "mini_icon: 0x%lx 0x%lx %dx%dx%d\n", (unsigned long) win->pic.picture, (unsigned long) win->pic.mask, win->pic.width, win->pic.height, win->pic.depth); } static void icon_location(FvwmPacketBody *body) { Ulong app_id = body->minimal_data.app_id; WinData *win; win = id_to_win(app_id); if (win == NULL) { return; } win->icon_g.x = body->icon_data.xpos; win->icon_g.y = body->icon_data.ypos; win->icon_g.width = body->icon_data.icon_width; if (win->icon_g.width <= 0) { win->icon_g.width = 1; } win->icon_g.height = body->icon_data.icon_height; if (win->icon_g.height <= 0) { win->icon_g.height = 1; } check_in_window(win); } static void iconify(FvwmPacketBody *body, int dir) { Ulong app_id = body->minimal_data.app_id; WinData *win; win = id_to_win(app_id); set_win_iconified(win, dir); icon_location(body); check_win_complete(win); check_in_window(win); } static void window_shade(FvwmPacketBody *body, int do_shade) { Window w; WinManager *man; w = (Window)(body->minimal_data.app_id); man = find_windows_manager(w); if (man == NULL) { return; } if (do_shade) { man->flags.needs_resize_after_unshade = 0; man->flags.is_shaded = 1; } else { man->flags.is_shaded = 0; if (man->flags.needs_resize_after_unshade) { draw_manager(man); man->flags.needs_resize_after_unshade = 0; } } return; } /* only used by remanage_winlist */ static void update_win_in_hashtab(void *arg) { WinData *p = (WinData *)arg; check_in_window(p); } void remanage_winlist(void) { walk_hashtab(update_win_in_hashtab); draw_managers(); } static void new_desk(FvwmPacketBody *body) { globals.desknum = body->new_desk_data.desknum; remanage_winlist(); } static void sendtomodule(FvwmPacketBody *body) { extern void execute_function(char *); Uchar *string = body->name_data.name.name; ConsoleDebug(FVWM, "Got string: %s\n", string); execute_function((char *)string); } static void property_change(FvwmPacketBody *body) { WinManager *man = NULL; int j; if (body->property_data.id != 0) { if (!(man = find_windows_manager(body->property_data.id))) return; } if (body->property_data.arg == MX_PROPERTY_CHANGE_BACKGROUND) { if (man != NULL && CSET_IS_TRANSPARENT_PR(man->colorsets[DEFAULT])) { recreate_background(man, DEFAULT); force_manager_redraw(man); } if (man != NULL) { return; } for (j = 0; j < globals.num_managers; j++) { man = &globals.managers[j]; if (CSET_IS_TRANSPARENT_PR(man->colorsets[DEFAULT])) { recreate_background(man, DEFAULT); force_manager_redraw(man); } } } else if (body->property_data.arg == MX_PROPERTY_CHANGE_SWALLOW && man != NULL) { man->swallowed = body->property_data.toggle; if (man->swallowed && body->property_data.str) { unsigned long u; if (sscanf((char *)body->property_data.str, "%lu", &u) == 1) { man->swallower_win = (Window)u; } else { man->swallower_win = 0; } } } } static void ProcessMessage(Ulong type, FvwmPacketBody *body) { int i; ConsoleDebug(FVWM, "fvwm message type: %ld\n", type); switch(type) { case M_CONFIG_INFO: ConsoleDebug(FVWM, "DEBUG::M_CONFIG_INFO\n"); handle_config_info((unsigned long*)body); break; case M_CONFIGURE_WINDOW: ConsoleDebug(FVWM, "DEBUG::M_CONFIGURE_WINDOW\n"); configure_window(body); break; case M_FOCUS_CHANGE: ConsoleDebug(FVWM, "DEBUG::M_FOCUS_CHANGE\n"); focus_change(body); break; case M_RES_NAME: ConsoleDebug(FVWM, "DEBUG::M_RES_NAME\n"); res_name(body); break; case M_RES_CLASS: ConsoleDebug(FVWM, "DEBUG::M_RES_CLASS\n"); class_name(body); break; case M_MAP: ConsoleDebug(FVWM, "DEBUG::M_MAP\n"); break; case M_ADD_WINDOW: ConsoleDebug(FVWM, "DEBUG::M_ADD_WINDOW\n"); new_window(body); break; case M_DESTROY_WINDOW: ConsoleDebug(FVWM, "DEBUG::M_DESTROY_WINDOW\n"); destroy_window(body); break; case M_MINI_ICON: ConsoleDebug(FVWM, "DEBUG::M_MINI_ICON\n"); mini_icon(body); break; case M_WINDOW_NAME: ConsoleDebug(FVWM, "DEBUG::M_WINDOW_NAME\n"); window_name(body); break; case M_VISIBLE_NAME: ConsoleDebug(FVWM, "DEBUG::M_VISIBLE_NAME\n"); visible_name(body); break; case M_ICON_NAME: ConsoleDebug(FVWM, "DEBUG::M_ICON_NAME\n"); icon_name(body); break; case MX_VISIBLE_ICON_NAME: ConsoleDebug(FVWM, "DEBUG::MX_VISIBLE_ICON_NAME\n"); visible_icon_name(body); break; case M_DEICONIFY: ConsoleDebug(FVWM, "DEBUG::M_DEICONIFY\n"); iconify(body, 0); SendUnlockNotification(fvwm_fd); break; case M_ICONIFY: ConsoleDebug(FVWM, "DEBUG::M_ICONIFY\n"); iconify(body, 1); SendUnlockNotification(fvwm_fd); break; case M_ICON_LOCATION: icon_location(body); break; case M_END_WINDOWLIST: ConsoleDebug(FVWM, "DEBUG::M_END_WINDOWLIST\n"); ConsoleDebug( FVWM, "+++++ End window list +++++\n"); if (globals.focus_win && globals.focus_win->button) { globals.focus_win->manager->focus_button = globals.focus_win->button; } globals.got_window_list = 1; for (i = 0; i < globals.num_managers; i++) { create_manager_window(i); } break; case M_NEW_DESK: ConsoleDebug(FVWM, "DEBUG::M_NEW_DESK\n"); new_desk(body); break; case M_NEW_PAGE: ConsoleDebug(FVWM, "DEBUG::M_NEW_PAGE\n"); if (globals.x == body->new_page_data.x && globals.y == body->new_page_data.y && globals.desknum == body->new_page_data.desknum) { ConsoleDebug(FVWM, "Useless NEW_PAGE received\n"); break; } globals.x = body->new_page_data.x; globals.y = body->new_page_data.y; globals.desknum = body->new_page_data.desknum; if (fvwm_focus_win && fvwm_focus_win->manager && fvwm_focus_win->manager->followFocus) { /* need to set the focus on a page change */ add_win_state(fvwm_focus_win, FOCUS_CONTEXT); } for (i = 0; i < globals.num_managers; i++) { set_draw_mode(&globals.managers[i], 0); } break; case M_STRING: ConsoleDebug(FVWM, "DEBUG::M_STRING\n"); sendtomodule(body); break; case MX_PROPERTY_CHANGE: ConsoleDebug(FVWM, "DEBUG::MX_PROPERTY_CHANGE\n"); property_change(body); break; case M_WINDOWSHADE: window_shade(body, 1); break; case M_DEWINDOWSHADE: window_shade(body, 0); break; default: break; } check_managers_consistency(); for (i = 0; i < globals.num_managers; i++) { if (drawing(&globals.managers[i])) { draw_manager(&globals.managers[i]); } } check_managers_consistency(); } void ReadFvwmPipe(void) { FvwmPacket* packet; PrintMemuse(); ConsoleDebug(FVWM, "DEBUG: entering ReadFvwmPipe\n"); if ((packet = ReadFvwmPacket(fvwm_fd[1])) == NULL) { exit(0); } else { ProcessMessage(packet->type, (FvwmPacketBody *)packet->body); } ConsoleDebug(FVWM, "DEBUG: leaving ReadFvwmPipe\n"); }