/* -*-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)) &&
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");
}
syntax highlighted by Code2HTML, v. 0.9.1