// bbsmount.cc for bbsmount - an tool for simple mounting in X11
//
// Copyright (c) 2001 by Miroslav Jezbera, jezberam@phoenix.inf.upol.cz
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// (See the included file COPYING / GPL-2.0)
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#endif /* STDC_HEADERS */
#if HAVE_SIGNAL_H
# include <signal.h>
#endif /* HAVE_SIGNAL_H */
#ifdef TIME_WITH_SYS_TIME
# include <time.h>
# include <sys/time.h>
#else /* !TIME_WITH_SYS_TIME */
# include <time.h>
#endif /* !TIME_WITH_SYS_TIME */
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif /* HAVE_SYS_PARAM_H */
#if HAVE_SYS_MOUNT_H
# include <sys/mount.h>
#endif /* HAVE_SYS_MOUNT_H */
#if HAVE_SYS_STATFS_H
# include <sys/statfs.h>
#endif /* HAVE_SYS_STATFS_H */
#if HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif /* HAVE_SYS_STATVFS_H */
#include <pthread.h>
#include <iostream>
#include <fstream>
#include "bbsmount.hh"
#include "i18n.hh"
#include "version.h"
#include "images/notfound.xpm"
#define USE_LARGER_UNIT(x) ((x) > 4096)
#define BUFFER_SIZE 1024
#if HAVE_STATVFS
# define STATFS statvfs
#elif HAVE_STATFS
# define STATFS statfs
#endif /* HAVE_STATVFS */
// Global variables
ToolWindow *AppWindow;
I18n i18n;
BToolTip tooltip;
bool finish_checking, do_reconfigure = false, is_statfs_filled = false;
string mount_point;
struct STATFS tooltip_statfs;
int debug_level;
// Functions
int
run_command_and_report_error(const char *command, string &err_msg)
{
string err_command = command, tmp_file;
int result;
char buffer[BUFFER_SIZE];
strcpy(buffer, "/tmp/."PACKAGE".XXXXXX");
#if HAVE_MKSTEMP
result = mkstemp(buffer);
if (result == -1)
perror("mkstemp");
else
close(result);
#elif HAVE_TMPNAM
if (!tmpnam(buffer))
perror("tmpnam");
#else /* !HAVE_TMPNAM && !HAVE_MKSTEMP */
if (!mktemp(buffer))
perror("mktemp");
#endif /* !HAVE_TMPNAM && !HAVE_MKSTEMP */
tmp_file = buffer;
err_command += " 2>";
err_command += tmp_file;
result = system(err_command.c_str());
if (result) {
ifstream err_file(tmp_file.c_str());
err_msg.erase();
do {
err_file.read(buffer, BUFFER_SIZE);
err_msg.append(buffer, err_file.gcount());
} while (err_file);
}
if (remove(tmp_file.c_str()))
perror("remove");
return result;
}
void *
run_command(void *data)
{
command_data_type *cd = (command_data_type *)data;
int retval;
string err_msg;
cd->mp->Lock();
retval = run_command_and_report_error(cd->command, err_msg);
if (retval == -1)
cd->mp->setLastError(err_msg);
else
cd->mp->clearError();
free(cd->command);
cd->mp->Unlock();
free(cd);
pthread_exit(NULL);
return NULL; // Never reached
}
int
run_command_in_foreground(const char *command, MountPoint &mp)
{
int retval;
string err_msg;
if (strlen(command) == 0)
return 0;
retval = run_command_and_report_error(command, err_msg);
if (retval == -1)
mp.setLastError(err_msg);
else
mp.clearError();
return retval;
}
int
run_command_in_background(const char *command, MountPoint &mp)
{
if (strlen(command) == 0)
return 0;
char *str = strdup(command); // prevents change and compiler warnings
command_data_type *data;
int retval = 0;
pthread_t run;
pthread_attr_t attribs;
data = (command_data_type *)malloc(sizeof(command_data_type));
if (data == NULL) {
fprintf(stderr, "bbsmount: Memory allocation failed!\n");
return -1;
}
data->command = str;
data->mp = ∓
if (pthread_attr_init(&attribs) != 0) {
perror("pthread_attr_init");
return -1;
}
if (pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED) != 0) {
perror("pthread_attr_setdetachstate");
pthread_attr_destroy(&attribs);
return -1;
}
if (pthread_create(&run, &attribs, run_command, (void *)data) != 0) {
perror("pthread_create");
retval = -1;
}
if (pthread_attr_destroy(&attribs) != 0)
perror("pthread_attr_destroy");
return retval;
}
set<int>
what_is_mounted(const map<string, int> &mount_points)
{
set<int> result;
map<string, int>::const_iterator pointer;
char buffer[max_mtab_line_length], md[max_mount_device_point_size], mp[max_mount_device_point_size];
FILE *mtab;
#if READ_MOUNT
mtab = popen(MOUNT_COMMAND, "r");
if (!mtab) {
fprintf(stderr, "Can't read output from mount command!");
return result;
}
#else /* !READ_MOUNT */
mtab = fopen(MTAB_FILE, "rt");
if (!mtab) {
fprintf(stderr, "Can't open mtab file!");
return result;
}
#endif /* !READ_MOUNT */
while (!feof(mtab)) {
if (fgets(buffer, max_mtab_line_length, mtab) > 0) {
#if READ_MOUNT
sscanf(buffer, "%s on %s", md, mp);
#else /* !READ_MOUNT */
sscanf(buffer, "%s %s", md, mp);
#endif /* !READ_MOUNT */
pointer = mount_points.find(string(mp));
if (pointer != mount_points.end())
result.insert(pointer->second);
}
}
#if READ_MOUNT
pclose(mtab);
#else /* !READ_MOUNT */
fclose(mtab);
#endif /* !READ_MOUNT */
return result;
}
bool
update_mount_points(const map<string, int> &mount_points)
{
set<int> result;
size_t count = AppWindow->GetMountPointsCount();
bool change = false;
int counter;
result = what_is_mounted(mount_points);
for (counter = 0; counter < (int)count; counter++)
if (AppWindow->GetMountPoint(counter).IsMounted() != (result.find(counter) != result.end())) {
AppWindow->GetMountPoint(counter).SetMounted(result.find(counter) != result.end());
change = true;
}
return change;
}
void
create_notify_event(void)
{
XEvent event;
memset((void *)&event, 0, sizeof(XExposeEvent));
event.type = Expose; /* How can I notify my thread waiting in XNextEvent, that there is some work ? */
event.xexpose.window = AppWindow->GetRootWindow();
event.xexpose.display = AppWindow->getXDisplay();
event.xexpose.send_event = True;
XSendEvent(AppWindow->getXDisplay(), AppWindow->GetRootWindow(), False, NoEventMask, &event);
XFlush(AppWindow->getXDisplay());
}
void *
check_mounts(void *param)
{
#if !READ_MOUNT
struct stat info;
int mtab_size = 0;
time_t mtab_time = time(NULL);
#endif /* !READ_MOUNT */
int return_value, counter;
map<string, int> mount_points;
struct STATFS new_stats;
for (counter = 0; counter < (int)AppWindow->GetMountPointsCount(); counter++)
mount_points[AppWindow->GetMountPoint(counter).GetMountPoint()] = counter;
while (!finish_checking) {
#if READ_MOUNT
if (update_mount_points(mount_points))
create_notify_event();
#else /* !READ_MOUNT */
stat(MTAB_FILE, &info);
if ((difftime(info.st_mtime, mtab_time) > 0) || (mtab_size != info.st_size)) {
mtab_size = info.st_size;
mtab_time = info.st_mtime;
if (update_mount_points(mount_points))
create_notify_event();
}
#endif /* !READ_MOUNT */
if (is_statfs_filled) {
if (STATFS(mount_point.c_str(), &new_stats) != 0)
perror("Can't get filesystem info!");
else {
if (new_stats.f_bfree != tooltip_statfs.f_bfree || new_stats.f_bavail != tooltip_statfs.f_bavail) {
memcpy((void *)&tooltip_statfs, (void *)&new_stats, sizeof(struct STATFS));
AppWindow->updateTooltip();
}
}
}
return_value = sleep(AppWindow->GetResources()->app.refresh_time);
if (return_value != 0)
finish_checking = true;
}
pthread_exit(NULL);
return NULL;
}
RETSIGTYPE
shutdown(int signal)
{
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Stopping bbsmount.\n");
#endif
finish_checking = true;
do_reconfigure = false;
AppWindow->Stop();
create_notify_event();
}
RETSIGTYPE
usersignal(int signal)
{
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Reconfiguring bbsmount.\n");
#endif
AppWindow->reconfigure();
}
ToolWindow::ToolWindow(int argc,char **argv,struct CMDOPTIONS *options) : Basewindow(argc,argv,options)
{
XrmInitialize();
resource = new Resource(this);
CreateWindow(false);
configure();
stop = false;
tooltip_for_mp = NULL;
}
ToolWindow::~ToolWindow(void)
{
XUnmapSubwindows(getXDisplay(), rootwin);
FreeAll();
XUnmapWindow(getXDisplay(), rootwin);
/* destroy pixmaps */
if (pixmap.frame)
getImageControl()->removeImage(pixmap.frame);
if (pixmap.draw)
getImageControl()->removeImage(pixmap.draw);
if (pixmap.draw_pressed)
getImageControl()->removeImage(pixmap.draw_pressed);
delete resource;
XDestroyWindow(getXDisplay(), rootwin);
XFlush(getXDisplay());
}
const MyImage &
ToolWindow::GetImage(const int imageidx) const
{
return *images[imageidx];
}
const MountPoint &
ToolWindow::GetMountPoint(const int mntidx) const
{
return mount_points[mntidx];
}
const PIXMAP &
ToolWindow::GetPixmaps(void) const
{
return pixmap;
}
size_t
ToolWindow::GetMountPointsCount(void) const
{
return mount_points.size();
}
MountPoint &
ToolWindow::GetMountPoint(const int mntidx)
{
return mount_points[mntidx];
}
string
ToolWindow::getTooltip(const string &format, const MountPoint &mp, bool actual_statfs) const
{
string result, pformat;
char buffer[1024], unit = '\0', last_unit = '\0';
unsigned int counter;
bool was_percent = false;
is_statfs_filled = actual_statfs;
mount_point = mp.GetMountPoint();
for (counter = 0; counter < format.length(); counter++) {
if (was_percent) {
was_percent = false;
switch (format[counter]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
pformat += format[counter];
was_percent = true;
break;
case 'B':
case 'k':
case 'M':
case 'G': // units
unit = format[counter];
was_percent = true;
break;
case 'u': // used
float used;
if (!is_statfs_filled) {
if (STATFS(mp.GetMountPoint().c_str(), &tooltip_statfs) != 0)
return string("Can't get filesystem info!");
is_statfs_filled = true;
}
pformat.insert(pformat.begin(), '%');
pformat += 'f';
used = (float)(tooltip_statfs.f_blocks - tooltip_statfs.f_bfree) * tooltip_statfs.f_bsize;
switch (unit) {
case 'B':
sprintf(buffer, pformat.c_str(), used);
break;
case 'k':
sprintf(buffer, pformat.c_str(), used / 1024);
break;
case 'M':
sprintf(buffer, pformat.c_str(), used / 1048576);
break;
case 'G':
sprintf(buffer, pformat.c_str(), used / 1073741824);
break;
default:
if (USE_LARGER_UNIT(used)) {
unit = 'k';
used /= 1024;
}
if (USE_LARGER_UNIT(used)) {
unit = 'M';
used /= 1024;
}
if (USE_LARGER_UNIT(used)) {
unit = 'G';
used /= 1024;
}
sprintf(buffer, pformat.c_str(), used);
break;
}
last_unit = unit;
result += buffer;
break;
case 'f': // free
float free;
if (!is_statfs_filled) {
if (STATFS(mp.GetMountPoint().c_str(), &tooltip_statfs) != 0)
return string("Can't get filesystem info!");
is_statfs_filled = true;
}
pformat.insert(pformat.begin(), '%');
pformat += 'f';
free = (float)tooltip_statfs.f_bavail * tooltip_statfs.f_bsize;
switch (unit) {
case 'B':
sprintf(buffer, pformat.c_str(), free);
break;
case 'k':
sprintf(buffer, pformat.c_str(), free / 1024);
break;
case 'M':
sprintf(buffer, pformat.c_str(), free / 1048576);
break;
case 'G':
sprintf(buffer, pformat.c_str(), free / 1073741824);
break;
default:
if (USE_LARGER_UNIT(free)) {
unit = 'k';
free /= 1024;
}
if (USE_LARGER_UNIT(free)) {
unit = 'M';
free /= 1024;
}
if (USE_LARGER_UNIT(free)) {
unit = 'G';
free /= 1024;
}
sprintf(buffer, pformat.c_str(), free);
break;
}
last_unit = unit;
result += buffer;
break;
case 't': // total
float total;
if (!is_statfs_filled) {
if (STATFS(mp.GetMountPoint().c_str(), &tooltip_statfs) != 0)
return string("Can't get filesystem info!");
is_statfs_filled = true;
}
pformat.insert(pformat.begin(), '%');
pformat += 'f';
total = (float)(tooltip_statfs.f_blocks - tooltip_statfs.f_bfree + tooltip_statfs.f_bavail) * tooltip_statfs.f_bsize;
switch (unit) {
case 'B':
sprintf(buffer, pformat.c_str(), total);
break;
case 'k':
sprintf(buffer, pformat.c_str(), total / 1024);
break;
case 'M':
sprintf(buffer, pformat.c_str(), total / 1048576);
break;
case 'G':
sprintf(buffer, pformat.c_str(), total / 1073741824);
break;
default:
if (USE_LARGER_UNIT(total)) {
unit = 'k';
total /= 1024;
}
if (USE_LARGER_UNIT(total)) {
unit = 'M';
total /= 1024;
}
if (USE_LARGER_UNIT(total)) {
unit = 'G';
total /= 1024;
}
sprintf(buffer, pformat.c_str(), total);
break;
}
last_unit = unit;
result += buffer;
break;
case 'v':
if (last_unit == 'k' || last_unit == 'M' || last_unit == 'G')
result += last_unit;
break;
case 'U': // used %
if (!is_statfs_filled) {
if (STATFS(mp.GetMountPoint().c_str(), &tooltip_statfs) != 0)
return string("Can't get filesystem info!");
is_statfs_filled = true;
}
pformat.insert(pformat.begin(), '%');
pformat += 'f';
sprintf(buffer, pformat.c_str(), 100.0 - (float)tooltip_statfs.f_bavail * 100/tooltip_statfs.f_blocks);
result += buffer;
break;
case 'F': // free %
if (!is_statfs_filled) {
if (STATFS(mp.GetMountPoint().c_str(), &tooltip_statfs) != 0)
return string("Can't get filesystem info!");
is_statfs_filled = true;
}
pformat.insert(pformat.begin(), '%');
pformat += 'f';
sprintf(buffer, pformat.c_str(), (float)tooltip_statfs.f_bavail * 100/tooltip_statfs.f_blocks);
result += buffer;
break;
case 'd': // description
pformat.insert(pformat.begin(), '%');
pformat += 's';
sprintf(buffer, pformat.c_str(), mp.getDescription().c_str());
result += buffer;
break;
case 's': // mount point
pformat.insert(pformat.begin(), '%');
pformat += 's';
sprintf(buffer, pformat.c_str(), mp.GetMountPoint().c_str());
result += buffer;
break;
case 'e': // last error
pformat.insert(pformat.begin(), '%');
pformat += 's';
sprintf(buffer, pformat.c_str(), mp.getLastError().c_str());
result += buffer;
break;
default:
result += format[counter];
break;
}
if (!was_percent) {
pformat.erase();
unit = '\0';
}
} else {
if (format[counter] == '%')
was_percent = true;
else
result += format[counter];
}
}
return result;
}
void
ToolWindow::FreeAll(void)
{
vector<MyImage *>::iterator pointer = images.begin();
vector<MountWindow *>::iterator mwpointer = mount_windows.begin();
mount_points.clear();
commands.clear();
infotexts.clear();
for (; pointer != images.end(); pointer++)
delete *pointer;
images.clear();
for (; mwpointer != mount_windows.end(); mwpointer++)
delete *mwpointer;
mount_windows.clear();
}
void
ToolWindow::rereadResources(void)
{
delete resource;
resource = new Resource(this);
}
void
ToolWindow::configure(void)
{
vector<string>::const_iterator pointer, end;
XpmImage new_image;
int image_counter;
commands = resource->GetCommands();
infotexts = resource->getInfoTexts();
mount_points = resource->GetMountPoints();
pointer = resource->GetImages().begin();
end = resource->GetImages().end();
XpmCreateXpmImageFromData(notfound_xpm, &new_image, NULL);
SetImage(0, new MyImage(getXDisplay(), rootwin, &new_image));
XpmFreeXpmImage(&new_image);
image_counter = 1;
for (; pointer != end; pointer++) {
File imagefile(pointer->c_str(), resource->GetImagePrefix().c_str());
MyImage *my_new_image;
if (imagefile.Exist()) {
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Loading Xpm image %s.\n", imagefile.GetPath());
#endif /* DEBUG */
if (XpmReadFileToXpmImage(imagefile.GetPath(), &new_image, NULL) != XpmSuccess) {
XpmCreateXpmImageFromData(notfound_xpm, &new_image, NULL);
#if DEBUG
printf("Can't read image data from file %s!\n", imagefile.GetPath());
#endif /* DEBUG */
}
}
else {
XpmCreateXpmImageFromData(notfound_xpm, &new_image, NULL);
#if DEBUG
printf("Can't find image file %s!\n", pointer->c_str());
#endif /* DEBUG */
}
my_new_image = new MyImage(getXDisplay(), rootwin, &new_image);
SetImage(image_counter++, my_new_image);
XpmFreeXpmImage(&new_image);
}
resource->FreeAll();
}
/*Display *
ToolWindow::GetDisplay(void)
{
return dpy;
}*/
Resource *
ToolWindow::GetResources(void)
{
return resource;
}
Window
ToolWindow::GetRootWindow(void)
{
return rootwin;
}
void
ToolWindow::CreateWindow(const bool do_reconfigure)
{
XSetWindowAttributes attrib;
XWMHints wmhints;
unsigned long create_mask;
create_mask = CWBackPixmap | CWOverrideRedirect | CWCursor | CWEventMask;
drawarea.width = resource->app.column_width * resource->app.columns;
drawarea.height = resource->app.row_height * resource->app.rows;
rootgeometry.width = resource->app.column_width * resource->app.columns +
resource->frame.bevelWidth * 2 + (resource->app.columns - 1) * resource->app.button_padding;
rootgeometry.height = resource->app.row_height * resource->app.rows +
resource->frame.bevelWidth * 2 + (resource->app.rows - 1) * resource->app.button_padding;
if (resource->position.mask & XNegative) {
resource->position.x = getCurrentScreenInfo()->getWidth() + resource->position.x - rootgeometry.width;
}
if (resource->position.mask & YNegative) {
resource->position.y = getCurrentScreenInfo()->getHeight() + resource->position.y - rootgeometry.height;
}
if (withdrawn) {
attrib.override_redirect = False;
wmhints.initial_state = WithdrawnState;
}
else {
attrib.override_redirect = True;
wmhints.initial_state = NormalState;
}
attrib.background_pixmap = ParentRelative;
attrib.cursor = getSessionCursor();
attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask |
FocusChangeMask | KeyPressMask | StructureNotifyMask;
pixmap.frame = getImageControl()->renderImage(rootgeometry.width, rootgeometry.height, &resource->frame.texture);
pixmap.draw = getImageControl()->renderImage(resource->app.column_width, resource->app.row_height, &resource->app.mount_texture);
pixmap.draw_pressed = getImageControl()->renderImage(resource->app.column_width, resource->app.row_height, &resource->app.mount_texture_pressed);
if (!do_reconfigure) {
rootwin = XCreateWindow(getXDisplay(), getCurrentScreenInfo()->getRootWindow(), resource->position.x, resource->position.y, rootgeometry.width,
rootgeometry.height, 0, getCurrentScreenInfo()->getDepth(), InputOutput, getCurrentScreenInfo()->getVisual(), create_mask, &attrib);
}
else
if (!withdrawn) {
XMoveResizeWindow(getXDisplay(), rootwin, resource->position.x, resource->position.y,
rootgeometry.width, rootgeometry.height);
}
else {
XResizeWindow(getXDisplay(), rootwin, rootgeometry.width, rootgeometry.height);
}
wmhints.flags = IconWindowHint | StateHint;
wmhints.icon_window = rootwin;
XSetStandardProperties(getXDisplay(), rootwin, BBTOOL, BBTOOL, None,
getArgv(), getArgc(), NULL);
XSetWMProtocols (getXDisplay(), rootwin, &wm_delete_window, 1);
XSetWMHints(getXDisplay(), rootwin, &wmhints);
if (!shape)
XSetWindowBackgroundPixmap(getXDisplay(), rootwin, pixmap.frame);
if (!do_reconfigure) {
XClearWindow(getXDisplay(), rootwin);
XMapWindow(getXDisplay(), rootwin);
}
}
void
ToolWindow::CreateSubWindows(const bool do_reconfigure)
{
int col = 0, row = 0;
vector<MountPoint>::iterator pointer;
vector<MountWindow *>::iterator mwpointer = mount_windows.begin();
if (!do_reconfigure) {
for (pointer = mount_points.begin(); pointer != mount_points.end(); pointer++) {
if (col == resource->app.columns) {
if (++row == resource->app.rows)
break;
col = 0;
}
mount_windows.push_back(new MountWindow(&*pointer, getXDisplay(), rootwin, resource->frame.bevelWidth +
col * resource->app.column_width + resource->app.button_padding * col,
resource->frame.bevelWidth + row * resource->app.row_height +
resource->app.button_padding * row, resource->app.column_width,
resource->app.row_height));
mount_windows.back()->Draw();
col++;
}
}
else
if (!withdrawn) {
for (; mwpointer != mount_windows.end(); mwpointer++)
delete *mwpointer;
mount_windows.clear();
for (pointer = mount_points.begin(); pointer != mount_points.end(); pointer++) {
if (col == resource->app.columns) {
if (++row == resource->app.rows)
break;
col = 0;
}
mount_windows.push_back(new MountWindow(&*pointer, getXDisplay(), rootwin, resource->frame.bevelWidth +
col * resource->app.column_width + resource->app.button_padding * col,
resource->frame.bevelWidth + row * resource->app.row_height +
resource->app.button_padding * row, resource->app.column_width,
resource->app.row_height));
mount_windows.back()->Draw();
col++;
}
}
else {
for (; mwpointer != mount_windows.end(); mwpointer++)
delete *mwpointer;
mount_windows.clear();
for (pointer = mount_points.begin(); pointer != mount_points.end(); pointer++) {
if (col == resource->app.columns) {
if (++row == resource->app.rows)
break;
col = 0;
}
mount_windows.push_back(new MountWindow(&*pointer, getXDisplay(), rootwin, resource->frame.bevelWidth +
col * resource->app.column_width + resource->app.button_padding * col,
resource->frame.bevelWidth + row * resource->app.row_height +
resource->app.button_padding * row, resource->app.column_width,
resource->app.row_height));
mount_windows.back()->Draw();
col++;
}
}
XMapSubwindows(getXDisplay(), rootwin);
}
void
ToolWindow::EventLoop(void)
{
XEvent event;
vector<MountWindow *>::iterator pointer;
unsigned int command;
while (!stop) {
XNextEvent(getXDisplay(), &event);
switch (event.type) {
case Expose:
if (stop)
return;
if (event.xexpose.window == rootwin) {
if (event.xexpose.send_event == True) {
for (pointer = mount_windows.begin(); pointer != mount_windows.end(); pointer++) {
(*pointer)->Update();
if ((*tooltip_for_mp) == (*pointer)->GetMountPoint())
updateTooltip();
}
}
else
Draw(event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height);
}
else {
for (pointer = mount_windows.begin(); pointer != mount_windows.end(); pointer++)
if (event.xexpose.window == (*pointer)->GetWindow()) {
(*pointer)->Draw(event.xexpose.x, event.xexpose.y, event.xexpose.width,
event.xexpose.height);
break;
}
tooltip.processEvent(event);
}
break;
case ButtonPress:
tooltip.hide();
is_statfs_filled = false;
tooltip_for_mp = NULL;
for (pointer = mount_windows.begin(); pointer != mount_windows.end(); pointer++)
if (event.xbutton.window == (*pointer)->GetWindow()) {
command = (*pointer)->GetMountPoint().GetCommand(event.xbutton.button, event.xbutton.state);
if (command) {
(*pointer)->SetPressed(true);
char *comm = (char *)malloc(sizeof(char) * (commands[command].length() + (*pointer)->GetMountPoint().GetMountPoint().length()));
sprintf(comm, commands[command].c_str(), (*pointer)->GetMountPoint().GetMountPoint().c_str());
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Executing command: `%s`\n", comm);
#endif /* DEBUG */
#if RUN_IN_BACKGROUND
run_command_in_background(comm, (*pointer)->GetMountPoint());
#else /* !RUN_IN_BACKGROUND */
run_command_in_foreground(comm, (*pointer)->GetMountPoint());
#endif /* !RUN_IN_BACKGROUND */
free(comm);
}
}
break;
case ButtonRelease:
tooltip.hide();
is_statfs_filled = false;
tooltip_for_mp = NULL;
for (pointer = mount_windows.begin(); pointer != mount_windows.end(); pointer++)
if (event.xbutton.window == (*pointer)->GetWindow())
(*pointer)->SetPressed(false);
break;
case MotionNotify:
if (tooltip.getTimeout()) {
tooltip.hide();
is_statfs_filled = false;
tooltip_for_mp = NULL;
ShowTooltip(event.xmotion.window, event.xmotion.x, event.xmotion.y, event.xmotion.x_root, event.xmotion.y_root);
}
break;
case EnterNotify:
tooltip.hide();
is_statfs_filled = false;
tooltip_for_mp = NULL;
ShowTooltip(event.xcrossing.window, event.xcrossing.x, event.xcrossing.y, event.xcrossing.x_root, event.xcrossing.y_root);
break;
case LeaveNotify:
tooltip.hide();
is_statfs_filled = false;
tooltip_for_mp = NULL;
break;
case ConfigureNotify:
#if DEBUG
if (debug_level >= dbg_all_work)
printf("ConfigureNotify detected.\n");
#endif /* DEBUG */
if (do_reconfigure)
return;
break;
}
}
}
void
ToolWindow::Draw(void)
{
XClearWindow(getXDisplay(), rootwin);
}
void
ToolWindow::Draw(const int x, const int y, const unsigned int width, const unsigned int height)
{
XClearArea(getXDisplay(), rootwin, x, y, width, height, False);
}
void
ToolWindow::SetCommand(const int cmdidx, const string command)
{
if (cmdidx == (int)commands.size())
commands.push_back(command);
else
commands[cmdidx] = command;
}
void
ToolWindow::SetImage(const int imgidx, MyImage *image)
{
if (imgidx == (int)images.size())
images.push_back(image);
else
images[imgidx] = image;
}
void
ToolWindow::SetMountPoint(const int mntidx, const MountPoint &mntpoint)
{
if (mntidx == (int)mount_points.size())
mount_points.push_back(mntpoint);
else
mount_points[mntidx] = mntpoint;
}
void
ToolWindow::Stop(void)
{
stop = true;
}
void
ToolWindow::ShowTooltip(const Window w, const int x, const int y, const int screen_x, const int screen_y)
{
int space_left, space_right, rootwin_width, win_no = 0;
XWindowAttributes attrs;
vector<MountWindow *>::iterator pointer;
XGetWindowAttributes(getXDisplay(), rootwin, &attrs);
space_left = screen_x - attrs.x;
space_right = getCurrentScreenInfo()->getWidth() - screen_x - attrs.x - attrs.width ;
rootwin_width = attrs.width;
for (pointer = mount_windows.begin(); pointer != mount_windows.end(); pointer++) {
if (w == (*pointer)->GetWindow()) {
XGetWindowAttributes(getXDisplay(), (*pointer)->GetWindow(), &attrs);
if (space_left > space_right)
tooltip.setPosition(space_left - attrs.x - x - 1, screen_y,
(win_no / resource->app.columns == resource->app.rows - 1 ? top_left : bottom_left));
else
tooltip.setPosition(space_left - attrs.x - x + rootwin_width + 1, screen_y,
(win_no / resource->app.columns == resource->app.rows - 1 ? top_right : bottom_right));
tooltip.setText(getTooltip(infotexts[(*pointer)->GetMountPoint().getCurrentInfo()], (*pointer)->GetMountPoint()));
tooltip_for_mp = &(*pointer)->GetMountPoint();
tooltip.show();
}
win_no++;
}
}
void
ToolWindow::updateTooltip(void) {
tooltip.setText(getTooltip(infotexts[tooltip_for_mp->getCurrentInfo()], *tooltip_for_mp, true));
}
void
ToolWindow::reconfigure(void)
{
XEvent event;
do_reconfigure = true;
memset((void *)&event, 0, sizeof(XConfigureEvent));
event.type = ConfigureNotify;
event.xexpose.window = AppWindow->GetRootWindow();
event.xexpose.display = AppWindow->getXDisplay();
event.xexpose.send_event = True;
XSendEvent(AppWindow->getXDisplay(), AppWindow->GetRootWindow(), False, NoEventMask, &event);
XFlush(AppWindow->getXDisplay());
}
int
main(int argc, char *argv[])
{
int result;
pthread_t check_thread;
void *thread_return;
struct CMDOPTIONS options;
#if DEBUG
if (debug_level >= dbg_summary && i18n.multibyte())
printf("Using multibyte strings.\n");
#endif
if (XInitThreads() == 0) {
perror("bbsmount: Can't initialize X11!");
exit(EXIT_FAILURE);
}
read_options(argc, argv, options);
AppWindow = new ToolWindow(argc, argv, &options);
AppWindow->CreateSubWindows(false);
#ifdef HAVE_SIGACTION
struct sigaction act;
act.sa_handler = shutdown;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
sigaction(SIGTERM, &act, 0);
act.sa_handler = usersignal;
sigaction(SIGUSR1, &act, 0);
#else /* !HAVE_SIGACTION */
signal(SIGINT, shutdown);
signal(SIGTERM, shutdown);
signal(SIGUSR1, usersignal);
#endif /* !HAVE_SIGACTION */
do {
if (do_reconfigure) {
// delete AppWindow;
// AppWindow = new ToolWindow(argc, argv, &options);
// AppWindow->CreateSubWindows(false);
AppWindow->FreeAll();
AppWindow->rereadResources();
AppWindow->CreateWindow(true);
AppWindow->configure();
AppWindow->CreateSubWindows(true);
}
finish_checking = false;
do_reconfigure = false;
result = pthread_create(&check_thread, NULL, check_mounts, NULL);
if (result != 0) {
perror("bbsmount: Can't create thread!");
exit(EXIT_FAILURE);
}
tooltip.setTimeout(AppWindow->GetResources()->getTooltipTimeout());
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Waiting for events.\n");
#endif
AppWindow->EventLoop();
#if DEBUG
if (debug_level >= dbg_all_work)
printf("Event loop ended.\n");
#endif
finish_checking = true;
result = pthread_join(check_thread, &thread_return);
if (result != 0) {
perror("bbsmount: Can't join thread!");
exit(EXIT_FAILURE);
}
} while (do_reconfigure);
delete AppWindow;
return EXIT_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1