📄 fm-desktop.c
字号:
/** fm-desktop.c: Desktop integration for PCManFM** Copyright (c) 2004 Brian Tarricone, <bjt23@cornell.edu>* Copyright (c) 2006 Hong Jen Yee (PCMan), <pcman.tw@gmail.com>** 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 Library 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.** Random portions taken from or inspired by the original xfdesktop for xfce4:* Copyright (C) 2002-2003 Jasper Huijsmans (huysmans@users.sourceforge.net)* Copyright (C) 2003 Benedikt Meurer <benedikt.meurer@unix-ag.uni-siegen.de>* X event forwarding code:* Copyright (c) 2004 Nils Rennebarth** This file is modified form xfdesktop.c of XFCE 4.4* to be used in PCMan File Manager.*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h>#include <string.h>#include <signal.h>#include <X11/Xlib.h>#include <X11/Xatom.h>#include <gmodule.h>#include <gdk/gdkx.h>#include <gdk/gdkkeysyms.h>#include <gtk/gtk.h>#include "fm-desktop.h"#include "working-area.h"#include "ptk-file-browser.h"#include "ptk-icon-view.h"#include "main-window.h"#include "settings.h"static GtkWidget **desktops;static gint n_screens;static guint busy_cursor = 0;static void resize_desktops();static GdkPixmap* set_bg_pixmap( GdkScreen* screen, PtkIconView* view, GdkRectangle* working_area );static voidevent_forward_to_rootwin( GdkScreen *gscreen, GdkEvent *event ){ XButtonEvent xev, xev2; Display *dpy = GDK_DISPLAY_XDISPLAY( gdk_screen_get_display( gscreen ) ); if ( event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE ) { if ( event->type == GDK_BUTTON_PRESS ) { xev.type = ButtonPress; /* * rox has an option to disable the next * instruction. it is called "blackbox_hack". Does * anyone know why exactly it is needed? */ XUngrabPointer( dpy, event->button.time ); } else xev.type = ButtonRelease; xev.button = event->button.button; xev.x = event->button.x; /* Needed for icewm */ xev.y = event->button.y; xev.x_root = event->button.x_root; xev.y_root = event->button.y_root; xev.state = event->button.state; xev2.type = 0; } else if ( event->type == GDK_SCROLL ) { xev.type = ButtonPress; xev.button = event->scroll.direction + 4; xev.x = event->scroll.x; /* Needed for icewm */ xev.y = event->scroll.y; xev.x_root = event->scroll.x_root; xev.y_root = event->scroll.y_root; xev.state = event->scroll.state; xev2.type = ButtonRelease; xev2.button = xev.button; } else return ; xev.window = GDK_WINDOW_XWINDOW( gdk_screen_get_root_window( gscreen ) ); xev.root = xev.window; xev.subwindow = None; xev.time = event->button.time; xev.same_screen = True; XSendEvent( dpy, xev.window, False, ButtonPressMask | ButtonReleaseMask, ( XEvent * ) & xev ); if ( xev2.type == 0 ) return ; /* send button release for scroll event */ xev2.window = xev.window; xev2.root = xev.root; xev2.subwindow = xev.subwindow; xev2.time = xev.time; xev2.x = xev.x; xev2.y = xev.y; xev2.x_root = xev.x_root; xev2.y_root = xev.y_root; xev2.state = xev.state; xev2.same_screen = xev.same_screen; XSendEvent( dpy, xev2.window, False, ButtonPressMask | ButtonReleaseMask, ( XEvent * ) & xev2 );}static gbooleanscroll_cb( GtkWidget *w, GdkEventScroll *evt, gpointer user_data ){ event_forward_to_rootwin( gtk_widget_get_screen( w ), ( GdkEvent* ) evt ); return TRUE;}static gbooleanbutton_cb( GtkWidget *w, GdkEventButton *evt, gpointer user_data ){ GdkScreen * gscreen = gtk_widget_get_screen( w ); gint button = evt->button; gint state = evt->state; if ( evt->type == GDK_BUTTON_PRESS ) { if ( button == 2 || ( button == 1 && ( state & GDK_SHIFT_MASK ) && ( state & GDK_CONTROL_MASK ) ) ) { return FALSE; } else if ( button == 3 || ( button == 1 && ( state & GDK_SHIFT_MASK ) ) ) { // popup_desktop_menu(gscreen, button, evt->time); return FALSE; } } return FALSE;}static gbooleanreload_idle_cb( gpointer data ){ return FALSE;}#if 0gbooleanclient_message_received( GtkWidget *w, GdkEventClient *evt, gpointer user_data ){ if ( evt->data_format == 8 ) { if ( !strcmp( RELOAD_MESSAGE, evt->data.b ) ) { g_idle_add ( ( GSourceFunc ) reload_idle_cb, NULL ); return TRUE; } else if ( !strcmp( MENU_MESSAGE, evt->data.b ) ) { popup_desktop_menu( gtk_widget_get_screen( w ), 0, GDK_CURRENT_TIME ); return TRUE; } else if ( !strcmp( WINDOWLIST_MESSAGE, evt->data.b ) ) { popup_windowlist( gtk_widget_get_screen( w ), 0, GDK_CURRENT_TIME ); return TRUE; } else if ( !strcmp( QUIT_MESSAGE, evt->data.b ) ) { gtk_main_quit(); return TRUE; } } return FALSE;}#endifstatic voidsighandler_cb( int sig ){ switch ( sig ) { case SIGUSR1: g_idle_add ( ( GSourceFunc ) reload_idle_cb, NULL ); break; default: gtk_main_quit(); break; }}staticGdkFilterReturn on_rootwin_event ( GdkXEvent *xevent, GdkEvent *event, gpointer data ){ XPropertyEvent * evt = ( XPropertyEvent* ) xevent; /* If the size of working area changed */ /* g_debug("%s\n", gdk_x11_get_xatom_name(evt->atom)); */ if ( evt->type == PropertyNotify && evt->atom == XInternAtom( evt->display, "_NET_WORKAREA", False ) ) { resize_desktops(); } return GDK_FILTER_TRANSLATE;}int fm_desktop_init(){ GdkDisplay * gdpy; gint i; Window xid; GtkSettings *settings; const gchar *message = NULL; gboolean already_running; gdpy = gdk_display_get_default(); n_screens = gdk_display_get_n_screens( gdpy ); desktops = g_new( GtkWidget *, n_screens ); for ( i = 0; i < n_screens; i++ ) { desktops[ i ] = fm_desktop_new( gdk_display_get_screen( gdpy, i ) ); gtk_widget_add_events( desktops[ i ], GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK ); g_signal_connect( G_OBJECT( desktops[ i ] ), "scroll-event", G_CALLBACK( scroll_cb ), NULL ); g_signal_connect_after( G_OBJECT( desktops[ i ] ), "button-press-event", G_CALLBACK( button_cb ), NULL ); gtk_widget_show_all( desktops[ i ] ); gdk_window_lower( desktops[ i ] ->window ); } signal( SIGPIPE, SIG_IGN ); signal( SIGHUP, sighandler_cb ); signal( SIGINT, sighandler_cb ); signal( SIGTERM, sighandler_cb ); signal( SIGUSR1, sighandler_cb ); return 0;}void fm_desktop_cleanup(){ int i; for ( i = 0; i < n_screens; i++ ) gtk_widget_destroy( desktops[ i ] ); g_free( desktops ); if ( busy_cursor > 0 ) g_source_remove( busy_cursor );}static gboolean remove_busy_cursor(){ int i; for ( i = 0; i < n_screens; i++ ) gdk_window_set_cursor ( desktops[ i ] ->window, NULL ); busy_cursor = 0; return FALSE;}static void show_busy_cursor(){ if ( busy_cursor > 0 ) g_source_remove( busy_cursor ); else { int i; for ( i = 0; i < n_screens; i++ ) { GdkCursor* cursor; cursor = gdk_cursor_new( GDK_WATCH ); gdk_window_set_cursor ( desktops[ i ] ->window, cursor ); gdk_cursor_unref( cursor ); } } busy_cursor = g_timeout_add( 1000, remove_busy_cursor, NULL );}static void on_open_item ( PtkFileBrowser* file_browser, const char* path, PtkOpenAction action, gpointer user_data ){ FMMainWindow * main_window = NULL; show_busy_cursor(); switch ( action ) { case PTK_OPEN_NEW_TAB: main_window = fm_main_window_get_last_active(); case PTK_OPEN_DIR: case PTK_OPEN_NEW_WINDOW: if ( !main_window ) main_window = FM_MAIN_WINDOW(fm_main_window_new()); gtk_window_set_default_size( GTK_WINDOW( main_window ), appSettings.width, appSettings.height ); fm_main_window_add_new_tab( main_window, path, appSettings.showSidePane, appSettings.sidePaneMode ); gtk_window_present ( GTK_WINDOW( main_window ) ); break; case PTK_OPEN_TERMINAL: fm_main_window_open_terminal( GTK_WINDOW( user_data ), path ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -