Adding upstream version 0.5.3.
[debian/lxpanel.git] / src / plugins / wincmd.c
CommitLineData
6cc5e1a6
DB
1/**
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <stdlib.h>
20
21#include <gdk-pixbuf/gdk-pixbuf.h>
22#include <glib/gi18n.h>
23
24#include "panel.h"
25#include "misc.h"
26#include "plugin.h"
27#include "dbg.h"
28
2ba86315
DB
29/* Commands that can be issued. */
30typedef enum {
31 WC_NONE,
32 WC_ICONIFY,
33 WC_SHADE
34} WindowCommand;
35
36/* Private context for window command plugin. */
6cc5e1a6 37typedef struct {
2ba86315
DB
38 char * image; /* Main icon */
39 WindowCommand button_1_command; /* Command for mouse button 1 */
40 WindowCommand button_2_command; /* Command for mouse button 2 */
41 gboolean toggle_preference; /* User preference: toggle iconify/shade and map */
42 gboolean toggle_state; /* State of toggle */
43} WinCmdPlugin;
6cc5e1a6 44
6cc5e1a6
DB
45static pair wincmd_pair [] = {
46 { WC_NONE, "none" },
47 { WC_ICONIFY, "iconify" },
48 { WC_SHADE, "shade" },
49 { 0, NULL },
50};
51
2ba86315
DB
52static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command);
53static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, Plugin * plugin);
54static int wincmd_constructor(Plugin * p, char ** fp);
55static void wincmd_destructor(Plugin * p);
56static void wincmd_apply_configuration(Plugin * p);
57static void wincmd_configure(Plugin * p, GtkWindow * parent);
58static void wincmd_save_configuration(Plugin * p, FILE * fp);
59static void wincmd_panel_configuration_changed(Plugin * p);
60
61/* Execute a window command. */
62static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command)
6cc5e1a6 63{
2ba86315
DB
64 /* Get the list of all windows. */
65 int client_count;
66 Window * client_list = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CLIENT_LIST, XA_WINDOW, &client_count);
67 if (client_list != NULL)
68 {
69 /* Loop over all windows. */
70 guint current_desktop = get_net_current_desktop();
71 int i;
72 for (i = 0; i < client_count; i++)
73 {
74 /* Get the desktop and window type properties. */
75 NetWMWindowType nwwt;
76 guint task_desktop = get_net_wm_desktop(client_list[i]);
77 get_net_wm_window_type(client_list[i], &nwwt);
78
79 /* If the task is visible on the current desktop and it is an ordinary window,
80 * execute the requested Iconify or Shade change. */
81 if (((task_desktop == -1) || (task_desktop == current_desktop))
82 && (( ! nwwt.dock) && ( ! nwwt.desktop) && ( ! nwwt.splash)))
83 {
84 switch (command)
85 {
86 case WC_NONE:
87 break;
88
89 case WC_ICONIFY:
90 if (( ! wc->toggle_preference) || (wc->toggle_state))
91 XIconifyWindow(GDK_DISPLAY(), client_list[i], DefaultScreen(GDK_DISPLAY()));
92 else
93 XMapWindow (GDK_DISPLAY(), client_list[i]);
94 break;
95
96 case WC_SHADE:
97 Xclimsg(client_list[i], a_NET_WM_STATE,
98 ((( ! wc->toggle_preference) || (wc->toggle_state)) ? a_NET_WM_STATE_ADD : a_NET_WM_STATE_REMOVE),
99 a_NET_WM_STATE_SHADED, 0, 0, 0);
100 break;
101 }
102 }
6cc5e1a6 103 }
2ba86315 104 XFree(client_list);
6cc5e1a6 105
2ba86315
DB
106 /* Toggle state change if configured. */
107 if (wc->toggle_preference)
108 wc->toggle_state = ! wc->toggle_state;
6cc5e1a6 109 }
6cc5e1a6
DB
110}
111
2ba86315
DB
112/* Handler for "clicked" signal on main widget. */
113static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, Plugin * plugin)
6cc5e1a6 114{
2ba86315
DB
115 WinCmdPlugin * wc = (WinCmdPlugin *) plugin->priv;
116
117 /* Standard right-click handling. */
118 if (plugin_button_press_event(widget, event, plugin))
6cc5e1a6 119 return TRUE;
6cc5e1a6 120
2ba86315
DB
121 /* Left-click to iconify. */
122 if (event->button == 1)
123 wincmd_execute(wc, WC_ICONIFY);
6cc5e1a6 124
2ba86315
DB
125 /* Middle-click to shade. */
126 else if (event->button == 2)
127 wincmd_execute(wc, WC_SHADE);
128
129 return TRUE;
6cc5e1a6
DB
130}
131
2ba86315
DB
132/* Plugin constructor. */
133static int wincmd_constructor(Plugin * p, char ** fp)
134{
135 /* Allocate plugin context and set into Plugin private data pointer. */
136 WinCmdPlugin * wc = g_new0(WinCmdPlugin, 1);
137 p->priv = wc;
6cc5e1a6 138
2ba86315
DB
139 /* Initialize to defaults. */
140 wc->button_1_command = WC_ICONIFY;
141 wc->button_2_command = WC_SHADE;
6cc5e1a6 142
2ba86315 143 /* Load parameters from the configuration file. */
6cc5e1a6 144 line s;
6cc5e1a6 145 s.len = 256;
2ba86315 146 if(fp != NULL)
6cc5e1a6 147 {
2ba86315
DB
148 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END)
149 {
150 if (s.type == LINE_NONE)
151 {
152 ERR("wincmd: illegal token %s\n", s.str);
153 return 0;
6cc5e1a6 154 }
2ba86315
DB
155 if (s.type == LINE_VAR)
156 {
157 if (g_ascii_strcasecmp(s.t[0], "Button1") == 0)
158 wc->button_1_command = str2num(wincmd_pair, s.t[1], WC_ICONIFY);
159 else if (g_ascii_strcasecmp(s.t[0], "Button2") == 0)
160 wc->button_2_command = str2num(wincmd_pair, s.t[1], WC_SHADE);
161 else if (g_ascii_strcasecmp(s.t[0], "image") == 0)
162 wc->image = expand_tilda(g_strdup(s.t[1]));
163 else if (g_ascii_strcasecmp(s.t[0], "Toggle") == 0)
164 wc->toggle_preference = str2num(bool_pair, s.t[1], 0);
165 else
166 ERR("wincmd: unknown var %s\n", s.t[0]);
167 }
168 else
169 {
170 ERR("wincmd: illegal in this context %s\n", s.str);
171 return 0;
6cc5e1a6
DB
172 }
173 }
174 }
6cc5e1a6 175
2ba86315
DB
176 /* Default the image if unspecified. */
177 if (wc->image == NULL)
178 wc->image = g_strdup("window-manager");
6cc5e1a6 179
2ba86315
DB
180 /* Allocate top level widget and set into Plugin widget pointer. */
181 p->pwid = fb_button_new_from_file(wc->image, p->panel->icon_size, p->panel->icon_size, PANEL_ICON_HIGHLIGHT, TRUE);
182 gtk_container_set_border_width(GTK_CONTAINER(p->pwid), 0);
183 g_signal_connect(G_OBJECT(p->pwid), "button_press_event", G_CALLBACK(wincmd_button_clicked), (gpointer) p);
184 gtk_widget_set_tooltip_text(p->pwid, _("Left click to iconify all windows. Middle click to shade them."));
6cc5e1a6 185
2ba86315
DB
186 /* Show the widget and return. */
187 gtk_widget_show(p->pwid);
188 return 1;
189}
6cc5e1a6 190
2ba86315
DB
191/* Plugin destructor. */
192static void wincmd_destructor(Plugin * p)
193{
194 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
195 g_free(wc->image);
196 g_free(wc);
197}
6cc5e1a6 198
2ba86315
DB
199/* Callback when the configuration dialog has recorded a configuration change. */
200static void wincmd_apply_configuration(Plugin * p)
201{
202 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
203 wc->toggle_state = FALSE;
6cc5e1a6
DB
204}
205
2ba86315
DB
206/* Callback when the configuration dialog is to be shown. */
207static void wincmd_configure(Plugin * p, GtkWindow * parent)
6cc5e1a6 208{
2ba86315
DB
209 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
210 GtkWidget * dlg = create_generic_config_dlg(
211 _(p->class->name),
212 GTK_WIDGET(parent),
213 (GSourceFunc) wincmd_apply_configuration, (gpointer) p,
214 _("Alternately iconify/shade and raise"), &wc->toggle_preference, CONF_TYPE_BOOL,
215 NULL);
216 gtk_window_present(GTK_WINDOW(dlg));
217}
218
6cc5e1a6 219
2ba86315
DB
220/* Save the configuration to the configuration file. */
221static void wincmd_save_configuration(Plugin * p, FILE * fp)
222{
223 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
224 lxpanel_put_str(fp, "image", wc->image);
225 lxpanel_put_str(fp, "Button1", num2str(wincmd_pair, wc->button_1_command, NULL));
226 lxpanel_put_str(fp, "Button2", num2str(wincmd_pair, wc->button_2_command, NULL));
227 lxpanel_put_bool(fp, "Toggle", wc->toggle_preference);
6cc5e1a6
DB
228}
229
2ba86315
DB
230/* Callback when panel configuration changes. */
231static void wincmd_panel_configuration_changed(Plugin * p)
232{
233 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
234 fb_button_set_from_file(p->pwid, wc->image, p->panel->icon_size, p->panel->icon_size, TRUE);
235}
6cc5e1a6 236
2ba86315 237/* Plugin descriptor. */
6cc5e1a6 238PluginClass wincmd_plugin_class = {
2ba86315
DB
239
240 PLUGINCLASS_VERSIONING,
6cc5e1a6
DB
241
242 type : "wincmd",
243 name : N_("Minimize All Windows"),
244 version: "1.0",
2ba86315 245 description : N_("Sends commands to all desktop windows.\nSupported commands are 1) iconify and 2) shade"),
6cc5e1a6
DB
246
247 constructor : wincmd_constructor,
248 destructor : wincmd_destructor,
2ba86315
DB
249 config : wincmd_configure,
250 save : wincmd_save_configuration,
251 panel_configuration_changed : wincmd_panel_configuration_changed
252
6cc5e1a6 253};