// 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 #if STDC_HEADERS # include # include #endif /* STDC_HEADERS */ #if HAVE_SIGNAL_H # include #endif /* HAVE_SIGNAL_H */ #ifdef TIME_WITH_SYS_TIME # include # include #else /* !TIME_WITH_SYS_TIME */ # include #endif /* !TIME_WITH_SYS_TIME */ #if HAVE_SYS_PARAM_H # include #endif /* HAVE_SYS_PARAM_H */ #if HAVE_SYS_MOUNT_H # include #endif /* HAVE_SYS_MOUNT_H */ #if HAVE_SYS_STATFS_H # include #endif /* HAVE_SYS_STATFS_H */ #if HAVE_SYS_STATVFS_H # include #endif /* HAVE_SYS_STATVFS_H */ #include #include #include #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 what_is_mounted(const map &mount_points) { set result; map::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 &mount_points) { set 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 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::iterator pointer = images.begin(); vector::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::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::iterator pointer; vector::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::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::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; }